added if expression
This commit is contained in:
@@ -38,7 +38,7 @@ This language is under active development, progress will be marked here as the l
|
|||||||
- [ ] Higher kinded types
|
- [ ] Higher kinded types
|
||||||
- [ ] Variadic generic types
|
- [ ] Variadic generic types
|
||||||
- [ ] Control Flow
|
- [ ] Control Flow
|
||||||
- [ ] If
|
- [x] If
|
||||||
- [ ] While
|
- [ ] While
|
||||||
- [ ] For
|
- [ ] For
|
||||||
- [ ] Enums
|
- [ ] Enums
|
||||||
|
|||||||
@@ -65,8 +65,20 @@ impl User {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn if_expression(): i64 {
|
||||||
|
if (true) {
|
||||||
|
return 6;
|
||||||
|
} else {
|
||||||
|
return 9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main(): i64 {
|
fn main(): i64 {
|
||||||
|
if (false) {
|
||||||
add(4, 4)
|
add(4, 4)
|
||||||
|
} else {
|
||||||
|
61
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// type TestTrait trait {
|
// type TestTrait trait {
|
||||||
|
|||||||
16
src/ast.rs
16
src/ast.rs
@@ -128,6 +128,12 @@ pub struct LiteralFloat {
|
|||||||
pub type_: TypeUsage,
|
pub type_: TypeUsage,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct LiteralBool {
|
||||||
|
pub value: Spanned<String>,
|
||||||
|
pub type_: TypeUsage,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct LiteralStruct {
|
pub struct LiteralStruct {
|
||||||
pub name: Identifier,
|
pub name: Identifier,
|
||||||
@@ -167,13 +173,23 @@ pub struct VariableUsage {
|
|||||||
pub type_: TypeUsage,
|
pub type_: TypeUsage,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct IfExpression {
|
||||||
|
pub condition: Expression,
|
||||||
|
pub block: Block,
|
||||||
|
pub else_: Option<Block>,
|
||||||
|
pub type_: TypeUsage,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum Subexpression {
|
pub enum Subexpression {
|
||||||
LiteralInt(LiteralInt),
|
LiteralInt(LiteralInt),
|
||||||
LiteralFloat(LiteralFloat),
|
LiteralFloat(LiteralFloat),
|
||||||
|
LiteralBool(LiteralBool),
|
||||||
LiteralStruct(LiteralStruct),
|
LiteralStruct(LiteralStruct),
|
||||||
FunctionCall(FunctionCall),
|
FunctionCall(FunctionCall),
|
||||||
VariableUsage(VariableUsage),
|
VariableUsage(VariableUsage),
|
||||||
|
If(IfExpression),
|
||||||
StructGetter(StructGetter),
|
StructGetter(StructGetter),
|
||||||
Block(Block),
|
Block(Block),
|
||||||
Op(Operation),
|
Op(Operation),
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ pub enum TypingError {
|
|||||||
FunctionCallNotAFunction {
|
FunctionCallNotAFunction {
|
||||||
// TODO: add position
|
// TODO: add position
|
||||||
},
|
},
|
||||||
|
#[error("`if` condition must be bool")]
|
||||||
|
IfConditionMustBeBool {
|
||||||
|
// TODO: add position
|
||||||
|
},
|
||||||
#[error("multiple errors")]
|
#[error("multiple errors")]
|
||||||
MultipleErrors { errors: Vec<TypingError> },
|
MultipleErrors { errors: Vec<TypingError> },
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ match {
|
|||||||
"fn",
|
"fn",
|
||||||
"return",
|
"return",
|
||||||
"let",
|
"let",
|
||||||
|
"true",
|
||||||
|
"false",
|
||||||
|
"if",
|
||||||
|
"else",
|
||||||
"=",
|
"=",
|
||||||
"type",
|
"type",
|
||||||
"struct",
|
"struct",
|
||||||
@@ -47,6 +51,15 @@ pub SpannedLiteralFloat: ast::LiteralFloat = {
|
|||||||
<literal_float:Spanned<LiteralFloat>> => ast::LiteralFloat{value: literal_float, type_: ast::TypeUsage::new_builtin("f64".to_string())}
|
<literal_float:Spanned<LiteralFloat>> => ast::LiteralFloat{value: literal_float, type_: ast::TypeUsage::new_builtin("f64".to_string())}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub LiteralBool: String = {
|
||||||
|
"true" => "true".to_string(),
|
||||||
|
"false" => "false".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
pub SpannedLiteralBool: ast::LiteralBool = {
|
||||||
|
<literal_bool:Spanned<LiteralBool>> => ast::LiteralBool{value: literal_bool, type_: ast::TypeUsage::new_builtin("bool".to_string())}
|
||||||
|
};
|
||||||
|
|
||||||
pub Identifier: String = {
|
pub Identifier: String = {
|
||||||
<i:r"[A-Za-z_][A-Za-z0-9_]*"> => i.to_string()
|
<i:r"[A-Za-z_][A-Za-z0-9_]*"> => i.to_string()
|
||||||
};
|
};
|
||||||
@@ -79,6 +92,11 @@ pub VariableUsage: ast::VariableUsage = {
|
|||||||
<identifier:SpannedIdentifier> => ast::VariableUsage{name: identifier, type_: ast::TypeUsage::new_unknown(&id_generator)}
|
<identifier:SpannedIdentifier> => ast::VariableUsage{name: identifier, type_: ast::TypeUsage::new_unknown(&id_generator)}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub IfExpression: ast::IfExpression = {
|
||||||
|
"if" "("<c:Expression>")" <b:Block> => ast::IfExpression{condition: c, block: b, else_: None, type_: ast::TypeUsage::new_unknown(&id_generator)},
|
||||||
|
"if" "("<c:Expression>")" <b:Block> "else" <e:Block> => ast::IfExpression{condition: c, block: b, else_: Some(e), type_: ast::TypeUsage::new_unknown(&id_generator)},
|
||||||
|
};
|
||||||
|
|
||||||
pub Expression: ast::Expression = {
|
pub Expression: ast::Expression = {
|
||||||
<l:Expression> "+" <r:Factor> => {
|
<l:Expression> "+" <r:Factor> => {
|
||||||
ast::Expression{
|
ast::Expression{
|
||||||
@@ -114,10 +132,12 @@ pub Factor: ast::Expression = {
|
|||||||
pub Term: ast::Expression = {
|
pub Term: ast::Expression = {
|
||||||
SpannedLiteralInt => ast::Expression{subexpression: Box::new(ast::Subexpression::LiteralInt(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)},
|
SpannedLiteralInt => ast::Expression{subexpression: Box::new(ast::Subexpression::LiteralInt(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)},
|
||||||
SpannedLiteralFloat => ast::Expression{subexpression: Box::new(ast::Subexpression::LiteralFloat(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)},
|
SpannedLiteralFloat => ast::Expression{subexpression: Box::new(ast::Subexpression::LiteralFloat(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)},
|
||||||
|
SpannedLiteralBool => ast::Expression{subexpression: Box::new(ast::Subexpression::LiteralBool(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)},
|
||||||
LiteralStruct => ast::Expression{subexpression: Box::new(ast::Subexpression::LiteralStruct(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)},
|
LiteralStruct => ast::Expression{subexpression: Box::new(ast::Subexpression::LiteralStruct(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)},
|
||||||
FunctionCall => ast::Expression{subexpression: Box::new(ast::Subexpression::FunctionCall(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)},
|
FunctionCall => ast::Expression{subexpression: Box::new(ast::Subexpression::FunctionCall(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)},
|
||||||
StructGetter => ast::Expression{subexpression: Box::new(ast::Subexpression::StructGetter(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)},
|
StructGetter => ast::Expression{subexpression: Box::new(ast::Subexpression::StructGetter(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)},
|
||||||
VariableUsage => ast::Expression{subexpression: Box::new(ast::Subexpression::VariableUsage(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)},
|
VariableUsage => ast::Expression{subexpression: Box::new(ast::Subexpression::VariableUsage(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)},
|
||||||
|
IfExpression => ast::Expression{subexpression: Box::new(ast::Subexpression::If(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)},
|
||||||
Block => ast::Expression{subexpression: Box::new(ast::Subexpression::Block(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)},
|
Block => ast::Expression{subexpression: Box::new(ast::Subexpression::Block(<>)), type_: ast::TypeUsage::new_unknown(&id_generator)},
|
||||||
"(" <e:Expression> ")" => e,
|
"(" <e:Expression> ")" => e,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ pub enum Function {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
Numeric(NumericValue),
|
Numeric(NumericValue),
|
||||||
|
Bool(bool),
|
||||||
Function(Function),
|
Function(Function),
|
||||||
Struct(Arc<Mutex<StructValue>>),
|
Struct(Arc<Mutex<StructValue>>),
|
||||||
Unit,
|
Unit,
|
||||||
@@ -204,6 +205,15 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
|||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
result.insert(
|
||||||
|
"bool".to_string(),
|
||||||
|
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(
|
||||||
|
ast::PrimitiveTypeDeclaration {
|
||||||
|
name: "bool".to_string(),
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
result.insert(
|
result.insert(
|
||||||
"!".to_string(),
|
"!".to_string(),
|
||||||
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(
|
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(
|
||||||
@@ -351,6 +361,14 @@ impl TreeWalkInterpreter {
|
|||||||
let value: f64 = literal_float.value.value.parse().unwrap();
|
let value: f64 = literal_float.value.value.parse().unwrap();
|
||||||
return ExpressionResult::Value(Value::Numeric(NumericValue::F64(value)));
|
return ExpressionResult::Value(Value::Numeric(NumericValue::F64(value)));
|
||||||
}
|
}
|
||||||
|
ast::Subexpression::LiteralBool(literal_bool) => {
|
||||||
|
let value: bool = if &literal_bool.value.value == "true" {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
return ExpressionResult::Value(Value::Bool(value));
|
||||||
|
}
|
||||||
ast::Subexpression::LiteralStruct(literal_struct) => {
|
ast::Subexpression::LiteralStruct(literal_struct) => {
|
||||||
let declaration = match &ctx.environment[&literal_struct.name.name.value] {
|
let declaration = match &ctx.environment[&literal_struct.name.name.value] {
|
||||||
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Struct(declaration)) => {
|
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Struct(declaration)) => {
|
||||||
@@ -423,6 +441,28 @@ impl TreeWalkInterpreter {
|
|||||||
};
|
};
|
||||||
return ExpressionResult::Value(variable_value);
|
return ExpressionResult::Value(variable_value);
|
||||||
}
|
}
|
||||||
|
ast::Subexpression::If(if_expression) => {
|
||||||
|
let condition = match self.with_expression(ctx, &if_expression.condition) {
|
||||||
|
ExpressionResult::Value(r) => r,
|
||||||
|
ExpressionResult::Return(r) => {
|
||||||
|
return ExpressionResult::Return(r);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match &condition {
|
||||||
|
Value::Bool(cond) => {
|
||||||
|
if cond.clone() {
|
||||||
|
return self.with_block(ctx, &if_expression.block);
|
||||||
|
} else {
|
||||||
|
return match &if_expression.else_ {
|
||||||
|
Some(else_) => self.with_block(ctx, else_),
|
||||||
|
None => ExpressionResult::Value(Value::Unit),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => panic!("TypeError: condition must be bool"),
|
||||||
|
}
|
||||||
|
}
|
||||||
ast::Subexpression::StructGetter(struct_getter) => {
|
ast::Subexpression::StructGetter(struct_getter) => {
|
||||||
let source = match self.with_expression(ctx, &struct_getter.source) {
|
let source = match self.with_expression(ctx, &struct_getter.source) {
|
||||||
ExpressionResult::Value(r) => r,
|
ExpressionResult::Value(r) => r,
|
||||||
|
|||||||
@@ -55,10 +55,10 @@ fn main() {
|
|||||||
let module_ast = grammar::ModuleParser::new()
|
let module_ast = grammar::ModuleParser::new()
|
||||||
.parse(&unknown_id_gen, &contents)
|
.parse(&unknown_id_gen, &contents)
|
||||||
.unwrap(); //TODO: convert to error
|
.unwrap(); //TODO: convert to error
|
||||||
println!("ast: {:#?}", &module_ast);
|
// println!("ast: {:#?}", &module_ast);
|
||||||
let alias_resolver = type_alias_resolution::TypeAliasResolver {};
|
let alias_resolver = type_alias_resolution::TypeAliasResolver {};
|
||||||
let resolved_ast = alias_resolver.with_module(&module_ast);
|
let resolved_ast = alias_resolver.with_module(&module_ast);
|
||||||
println!("resolved ast: {:#?}", &resolved_ast);
|
// println!("resolved ast: {:#?}", &resolved_ast);
|
||||||
let type_checker = type_checking::TypeChecker {};
|
let type_checker = type_checking::TypeChecker {};
|
||||||
let type_checking_result = type_checker.with_module(&resolved_ast);
|
let type_checking_result = type_checker.with_module(&resolved_ast);
|
||||||
match &type_checking_result {
|
match &type_checking_result {
|
||||||
|
|||||||
@@ -258,6 +258,12 @@ impl TypeAliasResolver {
|
|||||||
type_: process_type(ctx, &literal_float.type_),
|
type_: process_type(ctx, &literal_float.type_),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
ast::Subexpression::LiteralBool(literal_bool) => {
|
||||||
|
ast::Subexpression::LiteralBool(ast::LiteralBool {
|
||||||
|
value: literal_bool.value.clone(),
|
||||||
|
type_: process_type(ctx, &literal_bool.type_),
|
||||||
|
})
|
||||||
|
}
|
||||||
ast::Subexpression::LiteralStruct(literal_struct) => {
|
ast::Subexpression::LiteralStruct(literal_struct) => {
|
||||||
let result = resolve_type(
|
let result = resolve_type(
|
||||||
ctx,
|
ctx,
|
||||||
@@ -296,6 +302,17 @@ impl TypeAliasResolver {
|
|||||||
type_: process_type(ctx, &variable_usage.type_),
|
type_: process_type(ctx, &variable_usage.type_),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
ast::Subexpression::If(if_expression) => {
|
||||||
|
ast::Subexpression::If(ast::IfExpression {
|
||||||
|
condition: self.with_expression(ctx, &if_expression.condition),
|
||||||
|
block: self.with_block(ctx, &if_expression.block),
|
||||||
|
else_: match &if_expression.else_ {
|
||||||
|
Some(else_) => Some(self.with_block(ctx, else_)),
|
||||||
|
None => None,
|
||||||
|
},
|
||||||
|
type_: process_type(ctx, &if_expression.type_),
|
||||||
|
})
|
||||||
|
}
|
||||||
ast::Subexpression::StructGetter(struct_getter) => {
|
ast::Subexpression::StructGetter(struct_getter) => {
|
||||||
ast::Subexpression::StructGetter(ast::StructGetter {
|
ast::Subexpression::StructGetter(ast::StructGetter {
|
||||||
source: self.with_expression(ctx, &struct_getter.source),
|
source: self.with_expression(ctx, &struct_getter.source),
|
||||||
|
|||||||
@@ -120,6 +120,15 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
|||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
result.insert(
|
||||||
|
"bool".to_string(),
|
||||||
|
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(
|
||||||
|
ast::PrimitiveTypeDeclaration {
|
||||||
|
name: "bool".to_string(),
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
result.insert(
|
result.insert(
|
||||||
"!".to_string(),
|
"!".to_string(),
|
||||||
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(
|
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(
|
||||||
@@ -132,7 +141,7 @@ fn create_builtins() -> HashMap<String, NamedEntity> {
|
|||||||
"unit".to_string(),
|
"unit".to_string(),
|
||||||
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(
|
NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(
|
||||||
ast::PrimitiveTypeDeclaration {
|
ast::PrimitiveTypeDeclaration {
|
||||||
name: "!".to_string(),
|
name: "unit".to_string(),
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
@@ -798,6 +807,17 @@ impl TypeChecker {
|
|||||||
type_: apply_substitution(ctx, &substitution, &literal_float.type_)?,
|
type_: apply_substitution(ctx, &substitution, &literal_float.type_)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
ast::Subexpression::LiteralBool(literal_bool) => {
|
||||||
|
substitution = compose_substitutions(
|
||||||
|
ctx,
|
||||||
|
&substitution,
|
||||||
|
&unify(ctx, &expression.type_, &literal_bool.type_)?,
|
||||||
|
)?;
|
||||||
|
ast::Subexpression::LiteralBool(ast::LiteralBool {
|
||||||
|
value: literal_bool.value.clone(),
|
||||||
|
type_: apply_substitution(ctx, &substitution, &literal_bool.type_)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
ast::Subexpression::LiteralStruct(literal_struct) => {
|
ast::Subexpression::LiteralStruct(literal_struct) => {
|
||||||
substitution = compose_substitutions(
|
substitution = compose_substitutions(
|
||||||
ctx,
|
ctx,
|
||||||
@@ -926,6 +946,109 @@ impl TypeChecker {
|
|||||||
type_: apply_substitution(ctx, &substitution, &variable_usage.type_)?,
|
type_: apply_substitution(ctx, &substitution, &variable_usage.type_)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
ast::Subexpression::If(if_expression) => {
|
||||||
|
let (condition, subst) =
|
||||||
|
self.with_expression(ctx, &substitution, &if_expression.condition)?;
|
||||||
|
substitution = compose_substitutions(ctx, &substitution, &subst)?;
|
||||||
|
|
||||||
|
let (block_result, subst) =
|
||||||
|
self.with_block(ctx, &substitution, &if_expression.block)?;
|
||||||
|
substitution = compose_substitutions(ctx, &substitution, &subst)?;
|
||||||
|
|
||||||
|
let else_ = match &if_expression.else_ {
|
||||||
|
Some(else_) => {
|
||||||
|
let (result, subst) = self.with_block(ctx, &substitution, else_)?;
|
||||||
|
substitution = compose_substitutions(ctx, &substitution, &subst)?;
|
||||||
|
Some(result)
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
match &condition.type_ {
|
||||||
|
ast::TypeUsage::Named(named) => {
|
||||||
|
if named.name.name.value != "bool" {
|
||||||
|
return Err(errors::TypingError::IfConditionMustBeBool {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::TypeUsage::Function(_) => {
|
||||||
|
return Err(errors::TypingError::IfConditionMustBeBool {});
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut never_count = 0;
|
||||||
|
match &block_result.type_ {
|
||||||
|
ast::TypeUsage::Named(named) => {
|
||||||
|
if named.name.name.value != "!" {
|
||||||
|
substitution = compose_substitutions(
|
||||||
|
ctx,
|
||||||
|
&substitution,
|
||||||
|
&unify(ctx, &if_expression.type_, &block_result.type_)?,
|
||||||
|
)?;
|
||||||
|
} else {
|
||||||
|
never_count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
substitution = compose_substitutions(
|
||||||
|
ctx,
|
||||||
|
&substitution,
|
||||||
|
&unify(ctx, &if_expression.type_, &block_result.type_)?,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match &else_ {
|
||||||
|
Some(else_block) => {
|
||||||
|
match &else_block.type_ {
|
||||||
|
ast::TypeUsage::Named(named) => {
|
||||||
|
if named.name.name.value != "!" {
|
||||||
|
substitution = compose_substitutions(
|
||||||
|
ctx,
|
||||||
|
&substitution,
|
||||||
|
&unify(ctx, &if_expression.type_, &else_block.type_)?,
|
||||||
|
)?;
|
||||||
|
} else {
|
||||||
|
never_count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
substitution = compose_substitutions(
|
||||||
|
ctx,
|
||||||
|
&substitution,
|
||||||
|
&unify(ctx, &if_expression.type_, &else_block.type_)?,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
substitution = compose_substitutions(
|
||||||
|
ctx,
|
||||||
|
&substitution,
|
||||||
|
&unify(ctx, &if_expression.type_, &ast::new_unit())?,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let result_type = if never_count == 2 {
|
||||||
|
ast::new_never()
|
||||||
|
} else {
|
||||||
|
apply_substitution(ctx, &substitution, &if_expression.type_)?
|
||||||
|
};
|
||||||
|
|
||||||
|
substitution = compose_substitutions(
|
||||||
|
ctx,
|
||||||
|
&substitution,
|
||||||
|
&unify(ctx, &expression.type_, &result_type)?,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
ast::Subexpression::If(ast::IfExpression {
|
||||||
|
condition: condition,
|
||||||
|
block: block_result,
|
||||||
|
else_: else_,
|
||||||
|
type_: result_type,
|
||||||
|
})
|
||||||
|
}
|
||||||
ast::Subexpression::StructGetter(struct_getter) => {
|
ast::Subexpression::StructGetter(struct_getter) => {
|
||||||
let (source, subst) =
|
let (source, subst) =
|
||||||
self.with_expression(ctx, &substitution, &struct_getter.source)?;
|
self.with_expression(ctx, &substitution, &struct_getter.source)?;
|
||||||
|
|||||||
Reference in New Issue
Block a user