Skip to content

Commit 4bb20e4

Browse files
committed
feat(ty): implement type solving for traits and paths
1 parent 90086de commit 4bb20e4

3 files changed

Lines changed: 236 additions & 47 deletions

File tree

src/passes/thir_gen.rs

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::prelude::*;
22

3-
use crate::ty::{Constraints, Solver, TypeVars};
3+
use crate::ty::{Constraints, Solver, TypeVarId, TypeVars};
44

55
use hir::*;
66
use thir::Thir;
@@ -37,10 +37,19 @@ impl<'ctx, 'hir> Pass<'ctx, 'hir> for ThirGen<'ctx, 'hir> {
3737
thir_gen.add_function_constraints(function);
3838
}
3939

40+
// Add constraints for each trait implementation.
41+
for trait_implementation in thir_gen.hir.trait_implementations.keys() {
42+
thir_gen.add_trait_implementation(trait_implementation);
43+
}
44+
45+
// Collect trait implementations.
46+
let trait_implementations = thir_gen.hir.trait_implementations.keys().cloned().collect();
47+
4048
// Run the solver.
4149
let types = Solver::run(
4250
&mut thir_gen.ctx.types,
4351
&mut thir_gen.type_vars,
52+
&trait_implementations,
4453
&thir_gen.constraints,
4554
);
4655

@@ -65,13 +74,18 @@ impl<'ctx, 'hir> ThirGen<'ctx, 'hir> {
6574
fn add_function_declaration(&mut self, function_id: FunctionId) {
6675
let function = &self.hir[function_id];
6776

68-
self.constraints.equal(
69-
self.type_vars.intern(function.binding),
70-
self.type_vars.intern(self.ctx.types.function(
71-
function.signature.parameters.iter().map(|(_, ty)| *ty),
72-
function.signature.return_ty,
73-
)),
74-
);
77+
let binding = self.type_vars.intern(function.binding);
78+
let signature = self.signature_as_type_var(&function.signature);
79+
80+
self.constraints.equal(binding, signature);
81+
}
82+
83+
/// Produce a [`TypeVar`] for the given [`FunctionSignature`].
84+
fn signature_as_type_var(&mut self, signature: &FunctionSignature) -> TypeVarId {
85+
self.type_vars.intern(self.ctx.types.function(
86+
signature.parameters.iter().map(|(_, ty)| *ty),
87+
signature.return_ty,
88+
))
7589
}
7690

7791
fn add_function_constraints(&mut self, function_id: FunctionId) {
@@ -96,6 +110,32 @@ impl<'ctx, 'hir> ThirGen<'ctx, 'hir> {
96110
self.add_block_constraints(&ctx, function.entry);
97111
}
98112

113+
/// Add constraints required to check a trait implementation. Will ensure that all implemented
114+
/// methods match the signature of the trait, but does not verify whether all methods were
115+
/// implemented.
116+
fn add_trait_implementation(&mut self, implementation_key: &TraitImplementationKey) {
117+
let implementation = &self.hir[implementation_key];
118+
let target_trait = &self.hir[implementation_key.trait_id];
119+
120+
let implementing_ty = implementation_key.ty;
121+
122+
for (method_id, method) in implementation.methods.iter_pairs() {
123+
// Fetch the intended signature.
124+
let trait_method_signature = self.signature_as_type_var(
125+
&target_trait.methods[method_id]
126+
.clone()
127+
.with_self(implementing_ty),
128+
);
129+
130+
// Fetch the method signature.
131+
let implemented_signature = self.signature_as_type_var(&self.hir[*method].signature);
132+
133+
// Emit constraint that they're equal.
134+
self.constraints
135+
.equal(trait_method_signature, implemented_signature);
136+
}
137+
}
138+
99139
fn add_block_constraints(&mut self, ctx: &ConstraintCtx, block_id: BlockId) {
100140
let block = &self.hir[block_id];
101141

@@ -342,6 +382,25 @@ impl<'ctx, 'hir> ThirGen<'ctx, 'hir> {
342382
self.type_vars.intern(TypeVar::Field(lhs, *field)),
343383
);
344384
}
385+
Expression::Path(Path {
386+
ty,
387+
target_trait,
388+
item,
389+
}) => {
390+
let ty_var = self.type_vars.intern(*ty);
391+
392+
// Enforce the type implements the trait.
393+
self.constraints.implements(ty_var, *target_trait);
394+
395+
// This expression results in the signature of the trait item.
396+
let item_signature = self.hir[*target_trait].methods[*item]
397+
.clone()
398+
// Since the trait method signature is used, substitute `Self` with the current
399+
// type.
400+
.with_self(*ty);
401+
let signature_var = self.signature_as_type_var(&item_signature);
402+
self.constraints.equal(expression, signature_var);
403+
}
345404
}
346405
}
347406

src/ty/constraints.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{prelude::*, ty::TypeVarId};
1+
use crate::{ir::hir::TraitId, prelude::*, ty::TypeVarId};
22

33
use super::IntegerKind;
44

@@ -19,6 +19,8 @@ pub enum Constraint {
1919
},
2020
/// Variable is an aggregate with some number of fields..
2121
Aggregate(usize),
22+
/// Variable implements given trait.
23+
Implements(TraitId),
2224
}
2325

2426
#[derive(Clone, Debug, Default)]
@@ -91,6 +93,12 @@ impl Constraints {
9193
self.constraints
9294
.push((var.into(), Constraint::Aggregate(size)));
9395
}
96+
97+
/// Add a [`Constraint::Implements`] `target_trait`.
98+
pub fn implements(&mut self, var: impl Into<TypeVarId>, target_trait: TraitId) {
99+
self.constraints
100+
.push((var.into(), Constraint::Implements(target_trait)));
101+
}
94102
}
95103

96104
impl Deref for Constraints {

0 commit comments

Comments
 (0)