Skip to content

Commit

Permalink
Store the type of literal expressions in anticipation of aliases
Browse files Browse the repository at this point in the history
  • Loading branch information
Jordan Mackie authored and Jordan Mackie committed Oct 24, 2022
1 parent 0477330 commit 6a2aa48
Show file tree
Hide file tree
Showing 3 changed files with 198 additions and 25 deletions.
38 changes: 28 additions & 10 deletions crates/ditto-ast/src/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@ pub enum Expression {
span: Span,
/// `"string"`
value: String,
/// The type of this string literal.
/// Generally this will be `PrimType::String`, but it might have been aliased.
value_type: Type,
},
/// An integer literal.
Int {
Expand All @@ -165,6 +168,9 @@ pub enum Expression {
/// generated code.
/// 2. Storing as a string avoids overflow issues.
value: String,
/// The type of this integer literal.
/// Generally this will be `PrimType::Int`, but it might have been aliased.
value_type: Type,
},
/// A floating point number literal.
Float {
Expand All @@ -179,6 +185,9 @@ pub enum Expression {
/// generated code.
/// 2. Storing as a string avoids float overflow and precision issues.
value: String,
/// The type of this float literal.
/// Generally this will be `PrimType::Float`, but it might have been aliased.
value_type: Type,
},
/// `foo.bar`
RecordAccess {
Expand All @@ -199,6 +208,9 @@ pub enum Expression {
element_type: Type,
/// Array elements.
elements: Vec<Self>,
/// The type of this array literal.
/// Generally this will be `PrimType::Array(element_type)`, but it might have been aliased.
value_type: Type,
},
/// A record literal.
Record {
Expand All @@ -211,16 +223,25 @@ pub enum Expression {
True {
/// The source span for this expression.
span: Span,
/// The type of this `true` literal.
/// Generally this will be `PrimType::Bool`, but it might have been aliased.
value_type: Type,
},
/// `false`
False {
/// The source span for this expression.
span: Span,
/// The type of this `false` literal.
/// Generally this will be `PrimType::Bool`, but it might have been aliased.
value_type: Type,
},
/// `unit`
Unit {
/// The source span for this expression.
span: Span,
/// The type of this `unit` literal.
/// Generally this will be `PrimType::Unit`, but it might have been aliased.
value_type: Type,
},
}

Expand Down Expand Up @@ -258,23 +279,20 @@ impl Expression {
Self::ForeignVariable { variable_type, .. } => variable_type.clone(),
Self::ImportedVariable { variable_type, .. } => variable_type.clone(),
Self::RecordAccess { field_type, .. } => field_type.clone(),
Self::String { .. } => Type::PrimConstructor(PrimType::String),
Self::Int { .. } => Type::PrimConstructor(PrimType::Int),
Self::Float { .. } => Type::PrimConstructor(PrimType::Float),
Self::Array { element_type, .. } => Type::Call {
function: Box::new(Type::PrimConstructor(PrimType::Array)),
arguments: NonEmpty::new(element_type.clone()),
},
Self::Array { value_type, .. } => value_type.clone(),
Self::Record { fields, .. } => Type::RecordClosed {
kind: Kind::Type,
row: fields
.iter()
.map(|(label, element)| (label.clone(), element.get_type()))
.collect(),
},
Self::True { .. } => Type::PrimConstructor(PrimType::Bool),
Self::False { .. } => Type::PrimConstructor(PrimType::Bool),
Self::Unit { .. } => Type::PrimConstructor(PrimType::Unit),
Self::String { value_type, .. } => value_type.clone(),
Self::Int { value_type, .. } => value_type.clone(),
Self::Float { value_type, .. } => value_type.clone(),
Self::True { value_type, .. } => value_type.clone(),
Self::False { value_type, .. } => value_type.clone(),
Self::Unit { value_type, .. } => value_type.clone(),
}
}
/// Get the source span.
Expand Down
136 changes: 129 additions & 7 deletions crates/ditto-checker/src/typechecker/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,33 @@ pub fn typecheck_with(

pub fn infer(env: &Env, state: &mut State, expr: pre::Expression) -> Result<Expression> {
match expr {
pre::Expression::True { span } => Ok(Expression::True { span }),
pre::Expression::False { span } => Ok(Expression::False { span }),
pre::Expression::Unit { span } => Ok(Expression::Unit { span }),
pre::Expression::String { span, value } => Ok(Expression::String { span, value }),
pre::Expression::Int { span, value } => Ok(Expression::Int { span, value }),
pre::Expression::Float { span, value } => Ok(Expression::Float { span, value }),
pre::Expression::True { span } => Ok(Expression::True {
span,
value_type: Type::PrimConstructor(PrimType::Bool),
}),
pre::Expression::False { span } => Ok(Expression::False {
span,
value_type: Type::PrimConstructor(PrimType::Bool),
}),
pre::Expression::Unit { span } => Ok(Expression::Unit {
span,
value_type: Type::PrimConstructor(PrimType::Unit),
}),
pre::Expression::String { span, value } => Ok(Expression::String {
span,
value,
value_type: Type::PrimConstructor(PrimType::String),
}),
pre::Expression::Int { span, value } => Ok(Expression::Int {
span,
value,
value_type: Type::PrimConstructor(PrimType::Int),
}),
pre::Expression::Float { span, value } => Ok(Expression::Float {
span,
value,
value_type: Type::PrimConstructor(PrimType::Float),
}),
pre::Expression::Array { span, elements } => {
if let Some((head, tail)) = split_first_owned(elements) {
let head = infer(env, state, head)?;
Expand All @@ -142,18 +163,28 @@ pub fn infer(env: &Env, state: &mut State, expr: pre::Expression) -> Result<Expr
let element = check(env, state, element_type.clone(), element)?;
elements.push(element);
}
let value_type = Type::Call {
function: Box::new(Type::PrimConstructor(PrimType::Array)),
arguments: non_empty_vec::NonEmpty::new(element_type.clone()),
};
Ok(Expression::Array {
span,
element_type,
elements,
value_type,
})
} else {
let element_type = state.supply.fresh_type();
let elements = Vec::new();
let value_type = Type::Call {
function: Box::new(Type::PrimConstructor(PrimType::Array)),
arguments: non_empty_vec::NonEmpty::new(element_type.clone()),
};
Ok(Expression::Array {
span,
element_type,
elements,
value_type,
})
}
}
Expand Down Expand Up @@ -376,11 +407,15 @@ pub fn check(
.into_iter()
.map(|element| check(env, state, element_type.clone(), element))
.collect::<Result<Vec<_>>>()?;

let value_type = Type::Call {
function: Box::new(Type::PrimConstructor(PrimType::Array)),
arguments: non_empty_vec::NonEmpty::new(element_type.clone()),
};
Ok(Expression::Array {
span,
element_type,
elements,
value_type,
})
}
(
Expand Down Expand Up @@ -460,6 +495,93 @@ pub fn check(
}
Ok(Expression::Record { span, fields })
}
(pre::Expression::True { span }, expected) => {
unify(
state,
span,
Constraint {
expected: expected.clone(),
actual: Type::PrimConstructor(PrimType::Bool),
},
)?;
Ok(Expression::True {
span,
value_type: expected,
})
}
(pre::Expression::False { span }, expected) => {
unify(
state,
span,
Constraint {
expected: expected.clone(),
actual: Type::PrimConstructor(PrimType::Bool),
},
)?;
Ok(Expression::False {
span,
value_type: expected,
})
}
(pre::Expression::Unit { span }, expected) => {
unify(
state,
span,
Constraint {
expected: expected.clone(),
actual: Type::PrimConstructor(PrimType::Unit),
},
)?;
Ok(Expression::Unit {
span,
value_type: expected,
})
}
(pre::Expression::String { span, value }, expected) => {
unify(
state,
span,
Constraint {
expected: expected.clone(),
actual: Type::PrimConstructor(PrimType::String),
},
)?;
Ok(Expression::String {
span,
value,
value_type: expected,
})
}
(pre::Expression::Int { span, value }, expected) => {
unify(
state,
span,
Constraint {
expected: expected.clone(),
actual: Type::PrimConstructor(PrimType::Int),
},
)?;
Ok(Expression::Int {
span,
value,
value_type: expected,
})
}
(pre::Expression::Float { span, value }, expected) => {
unify(
state,
span,
Constraint {
expected: expected.clone(),
actual: Type::PrimConstructor(PrimType::Float),
},
)?;
Ok(Expression::Float {
span,
value,
value_type: expected,
})
}
(expr, expected) => {
let expression = infer(env, state, expr)?;
unify(
Expand Down
49 changes: 41 additions & 8 deletions crates/ditto-checker/src/typechecker/substitution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,13 +290,15 @@ impl Substitution {
span,
element_type,
elements,
value_type,
} => Array {
span,
element_type: self.apply(element_type),
elements: elements
.into_iter()
.map(|element| self.apply_expression(element))
.collect(),
value_type: self.apply(value_type),
},
Record { span, fields } => Record {
span,
Expand All @@ -316,14 +318,45 @@ impl Substitution {
target: Box::new(self.apply_expression(target)),
label,
},

// noop
True { .. } => expression,
False { .. } => expression,
Unit { .. } => expression,
String { .. } => expression,
Int { .. } => expression,
Float { .. } => expression,
True { span, value_type } => True {
span,
value_type: self.apply(value_type),
},
False { span, value_type } => False {
span,
value_type: self.apply(value_type),
},
Unit { span, value_type } => Unit {
span,
value_type: self.apply(value_type),
},
String {
span,
value,
value_type,
} => String {
span,
value,
value_type: self.apply(value_type),
},
Int {
span,
value,
value_type,
} => Int {
span,
value,
value_type: self.apply(value_type),
},
Float {
span,
value,
value_type,
} => Float {
span,
value,
value_type: self.apply(value_type),
},
}
}

Expand Down

0 comments on commit 6a2aa48

Please sign in to comment.