Skip to content

Commit 33edc41

Browse files
committed
Apply freshening when checking instance members
This fixes the 228 test case by introducing a proper instantiation step for rigid type variables from the instance head canonical. This creates fresh rigid type variables with update depths, fixing issues with the escape check in promote_type and subsequently, unification. This also changes the representation of Bindings::implicit to be based on Vec instead of HashMap. This enables trivial shadowing, ensuring that implicit type variables are kept up to date after instantiation.
1 parent 9bde3a4 commit 33edc41

4 files changed

Lines changed: 183 additions & 187 deletions

File tree

compiler-core/checking2/src/source.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,10 @@ pub use type_items::check_type_items;
1616

1717
use building_types::QueryResult;
1818

19-
use crate::ExternalQueries;
2019
use crate::context::CheckContext;
2120
use crate::core::{Type, TypeId, normalise};
2221
use crate::state::CheckState;
23-
use crate::safe_loop;
22+
use crate::{ExternalQueries, safe_loop};
2423

2524
fn is_binary_operator_type<Q>(
2625
state: &mut CheckState,

compiler-core/checking2/src/source/term_items.rs

Lines changed: 121 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,7 @@ where
217217
item_id,
218218
member,
219219
(class_file, class_id),
220-
&instance.constraints,
221-
&instance.arguments,
220+
&instance,
222221
)?;
223222
}
224223
}
@@ -233,8 +232,7 @@ fn check_instance_member_group<Q>(
233232
instance_item_id: TermItemId,
234233
member: &lowering::InstanceMemberGroup,
235234
(class_file, class_id): (FileId, TypeItemId),
236-
instance_constraints: &[TypeId],
237-
instance_arguments: &[TypeId],
235+
instance: &toolkit::DecomposedInstance,
238236
) -> QueryResult<()>
239237
where
240238
Q: ExternalQueries,
@@ -246,8 +244,7 @@ where
246244
context,
247245
member,
248246
(class_file, class_id),
249-
instance_constraints,
250-
instance_arguments,
247+
instance,
251248
)
252249
})
253250
})
@@ -258,93 +255,137 @@ fn check_instance_member_group_core<Q>(
258255
context: &CheckContext<Q>,
259256
member: &lowering::InstanceMemberGroup,
260257
(class_file, class_id): (FileId, TypeItemId),
261-
instance_constraints: &[TypeId],
262-
instance_arguments: &[TypeId],
258+
instance: &toolkit::DecomposedInstance,
263259
) -> QueryResult<()>
264260
where
265261
Q: ExternalQueries,
266262
{
267-
for &constraint in instance_constraints {
268-
state.push_given(constraint);
269-
}
263+
let FreshenedInstanceRigids {
264+
constraints: instance_constraints,
265+
arguments: instance_arguments,
266+
substitution,
267+
} = freshen_instance_rigids(state, context, instance)?;
268+
269+
state.with_implicit(context, &substitution, |state| {
270+
for &constraint in &instance_constraints {
271+
state.push_given(constraint);
272+
}
270273

271-
let class_member_type = if let Some((member_file, member_id)) = member.resolution {
272-
Some(toolkit::lookup_file_term(state, context, member_file, member_id)?)
273-
} else {
274-
None
275-
};
274+
let class_member_type = if let Some((member_file, member_id)) = member.resolution {
275+
Some(toolkit::lookup_file_term(state, context, member_file, member_id)?)
276+
} else {
277+
None
278+
};
276279

277-
let class_member_type = if let Some(class_member_type) = class_member_type {
278-
specialise_class_member_type(
279-
state,
280-
context,
281-
class_member_type,
282-
(class_file, class_id),
283-
instance_arguments,
284-
)?
285-
} else {
286-
None
287-
};
280+
let class_member_type = if let Some(class_member_type) = class_member_type {
281+
specialise_class_member_type(
282+
state,
283+
context,
284+
class_member_type,
285+
(class_file, class_id),
286+
&instance_arguments,
287+
)?
288+
} else {
289+
None
290+
};
288291

289-
let residuals = if let Some(signature_id) = member.signature {
290-
let (signature_member_type, _) =
291-
types::check_kind(state, context, signature_id, context.prim.t)?;
292-
293-
if let Some(class_member_type) = class_member_type {
294-
let unified =
295-
unification::unify(state, context, signature_member_type, class_member_type)?;
296-
if !unified {
297-
let expected = state.pretty_id(context, class_member_type)?;
298-
let actual = state.pretty_id(context, signature_member_type)?;
299-
state.insert_error(ErrorKind::InstanceMemberTypeMismatch { expected, actual });
292+
let residuals = if let Some(signature_id) = member.signature {
293+
let (signature_member_type, _) =
294+
types::check_kind(state, context, signature_id, context.prim.t)?;
295+
296+
if let Some(class_member_type) = class_member_type {
297+
let unified =
298+
unification::unify(state, context, signature_member_type, class_member_type)?;
299+
if !unified {
300+
let expected = state.pretty_id(context, class_member_type)?;
301+
let actual = state.pretty_id(context, signature_member_type)?;
302+
state.insert_error(ErrorKind::InstanceMemberTypeMismatch { expected, actual });
303+
}
300304
}
305+
306+
let equation_set = equations::analyse_equation_set(
307+
state,
308+
context,
309+
equations::EquationMode::Check {
310+
origin: equations::EquationTypeOrigin::Explicit(signature_id),
311+
expected_type: signature_member_type,
312+
},
313+
&member.equations,
314+
)?;
315+
let exhaustiveness = equations::compute_equation_exhaustiveness(
316+
state,
317+
context,
318+
&equation_set,
319+
&member.equations,
320+
)?;
321+
state.report_exhaustiveness(context, exhaustiveness);
322+
state.solve_constraints(context)?
323+
} else if let Some(specialised_type) = class_member_type {
324+
let equation_set = equations::analyse_equation_set(
325+
state,
326+
context,
327+
equations::EquationMode::Check {
328+
origin: equations::EquationTypeOrigin::Implicit,
329+
expected_type: specialised_type,
330+
},
331+
&member.equations,
332+
)?;
333+
let exhaustiveness = equations::compute_equation_exhaustiveness(
334+
state,
335+
context,
336+
&equation_set,
337+
&member.equations,
338+
)?;
339+
state.report_exhaustiveness(context, exhaustiveness);
340+
state.solve_constraints(context)?
341+
} else {
342+
vec![]
343+
};
344+
345+
for residual in residuals {
346+
let constraint = state.pretty_id(context, residual)?;
347+
state.insert_error(ErrorKind::NoInstanceFound { constraint });
301348
}
302349

303-
let equation_set = equations::analyse_equation_set(
304-
state,
305-
context,
306-
equations::EquationMode::Check {
307-
origin: equations::EquationTypeOrigin::Explicit(signature_id),
308-
expected_type: signature_member_type,
309-
},
310-
&member.equations,
311-
)?;
312-
let exhaustiveness = equations::compute_equation_exhaustiveness(
313-
state,
314-
context,
315-
&equation_set,
316-
&member.equations,
317-
)?;
318-
state.report_exhaustiveness(context, exhaustiveness);
319-
state.solve_constraints(context)?
320-
} else if let Some(specialised_type) = class_member_type {
321-
let equation_set = equations::analyse_equation_set(
322-
state,
323-
context,
324-
equations::EquationMode::Check {
325-
origin: equations::EquationTypeOrigin::Implicit,
326-
expected_type: specialised_type,
327-
},
328-
&member.equations,
329-
)?;
330-
let exhaustiveness = equations::compute_equation_exhaustiveness(
331-
state,
332-
context,
333-
&equation_set,
334-
&member.equations,
335-
)?;
336-
state.report_exhaustiveness(context, exhaustiveness);
337-
state.solve_constraints(context)?
338-
} else {
339-
vec![]
340-
};
350+
Ok(())
351+
})
352+
}
353+
354+
struct FreshenedInstanceRigids {
355+
constraints: Vec<TypeId>,
356+
arguments: Vec<TypeId>,
357+
substitution: NameToType,
358+
}
359+
360+
fn freshen_instance_rigids<Q>(
361+
state: &mut CheckState,
362+
context: &CheckContext<Q>,
363+
instance: &toolkit::DecomposedInstance,
364+
) -> QueryResult<FreshenedInstanceRigids>
365+
where
366+
Q: ExternalQueries,
367+
{
368+
let mut substitution = NameToType::default();
341369

342-
for residual in residuals {
343-
let constraint = state.pretty_id(context, residual)?;
344-
state.insert_error(ErrorKind::NoInstanceFound { constraint });
370+
for binder in &instance.binders {
371+
let kind = SubstituteName::many(state, context, &substitution, binder.kind)?;
372+
let rigid = state.fresh_rigid(context.queries, kind);
373+
substitution.insert(binder.name, rigid);
345374
}
346375

347-
Ok(())
376+
let constraints = instance
377+
.constraints
378+
.iter()
379+
.map(|&constraint| SubstituteName::many(state, context, &substitution, constraint))
380+
.collect::<QueryResult<Vec<_>>>()?;
381+
382+
let arguments = instance
383+
.arguments
384+
.iter()
385+
.map(|&argument| SubstituteName::many(state, context, &substitution, argument))
386+
.collect::<QueryResult<Vec<_>>>()?;
387+
388+
Ok(FreshenedInstanceRigids { constraints, arguments, substitution })
348389
}
349390

350391
fn specialise_class_member_type<Q>(

compiler-core/checking2/src/state.rs

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::context::CheckContext;
1111
use crate::core::exhaustive::{
1212
ExhaustivenessReport, Pattern, PatternConstructor, PatternId, PatternInterner, PatternKind,
1313
};
14+
use crate::core::substitute::{NameToType, SubstituteName};
1415
use crate::core::{Depth, Name, SmolStrId, Type, TypeId, constraint, pretty, zonk};
1516
use crate::error::{CheckError, ErrorCrumb, ErrorKind};
1617
use crate::implication::Implications;
@@ -84,18 +85,25 @@ impl Unifications {
8485
/// Tracks type variable bindings during kind inference.
8586
#[derive(Default)]
8687
pub struct Bindings {
87-
forall_bindings: FxHashMap<lowering::TypeVariableBindingId, (Name, TypeId)>,
88-
implicit_bindings:
89-
FxHashMap<(lowering::GraphNodeId, lowering::ImplicitBindingId), (Name, TypeId)>,
88+
forall: FxHashMap<lowering::TypeVariableBindingId, (Name, TypeId)>,
89+
implicit: Vec<ImplicitBinding>,
90+
}
91+
92+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
93+
struct ImplicitBinding {
94+
node: lowering::GraphNodeId,
95+
id: lowering::ImplicitBindingId,
96+
name: Name,
97+
kind: TypeId,
9098
}
9199

92100
impl Bindings {
93101
pub fn bind_forall(&mut self, id: lowering::TypeVariableBindingId, name: Name, kind: TypeId) {
94-
self.forall_bindings.insert(id, (name, kind));
102+
self.forall.insert(id, (name, kind));
95103
}
96104

97105
pub fn lookup_forall(&self, id: lowering::TypeVariableBindingId) -> Option<(Name, TypeId)> {
98-
self.forall_bindings.get(&id).copied()
106+
self.forall.get(&id).copied()
99107
}
100108

101109
pub fn bind_implicit(
@@ -105,15 +113,44 @@ impl Bindings {
105113
name: Name,
106114
kind: TypeId,
107115
) {
108-
self.implicit_bindings.insert((node, id), (name, kind));
116+
self.implicit.push(ImplicitBinding { node, id, name, kind });
117+
}
118+
119+
fn bind_implicit_substitution<Q>(
120+
state: &mut CheckState,
121+
context: &CheckContext<Q>,
122+
substitution: &NameToType,
123+
) -> QueryResult<()>
124+
where
125+
Q: ExternalQueries,
126+
{
127+
let scope = state.bindings.implicit.len();
128+
129+
for binding in 0..scope {
130+
let ImplicitBinding { node, id, name, kind } = state.bindings.implicit[binding];
131+
let Some(&replacement) = substitution.get(&name) else { continue };
132+
133+
let Type::Rigid(name, _, _) = context.lookup_type(replacement) else {
134+
unreachable!("invariant violated: expected a rigid variable");
135+
};
136+
137+
let kind = SubstituteName::many(state, context, substitution, kind)?;
138+
state.bindings.implicit.push(ImplicitBinding { node, id, name, kind });
139+
}
140+
141+
Ok(())
109142
}
110143

111144
pub fn lookup_implicit(
112145
&self,
113146
node: lowering::GraphNodeId,
114147
id: lowering::ImplicitBindingId,
115148
) -> Option<(Name, TypeId)> {
116-
self.implicit_bindings.get(&(node, id)).copied()
149+
self.implicit
150+
.iter()
151+
.rev()
152+
.find(|binding| binding.node == node && binding.id == id)
153+
.map(|binding| (binding.name, binding.kind))
117154
}
118155
}
119156

@@ -199,6 +236,23 @@ impl CheckState {
199236
result
200237
}
201238

239+
pub fn with_implicit<Q, T>(
240+
&mut self,
241+
context: &CheckContext<Q>,
242+
substitution: &NameToType,
243+
f: impl FnOnce(&mut CheckState) -> QueryResult<T>,
244+
) -> QueryResult<T>
245+
where
246+
Q: ExternalQueries,
247+
{
248+
let scope = self.bindings.implicit.len();
249+
Bindings::bind_implicit_substitution(self, context, substitution)?;
250+
let result = f(self);
251+
self.bindings.implicit.truncate(scope);
252+
253+
result
254+
}
255+
202256
pub fn solve_constraints<Q>(&mut self, context: &CheckContext<Q>) -> QueryResult<Vec<TypeId>>
203257
where
204258
Q: ExternalQueries,

0 commit comments

Comments
 (0)