Skip to content

Commit 0fe860c

Browse files
committed
Preserve function subtyping in application-based functions
1 parent ec12f30 commit 0fe860c

File tree

2 files changed

+45
-37
lines changed
  • compiler-core/checking2/src/core
  • tests-integration/fixtures/checking2/260_hidden_forall_compose_application_subtype

2 files changed

+45
-37
lines changed

compiler-core/checking2/src/core/unification.rs

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use smol_str::SmolStr;
99
use crate::ExternalQueries;
1010
use crate::context::CheckContext;
1111
use crate::core::substitute::SubstituteName;
12-
use crate::core::{Depth, Name, RowField, RowType, RowTypeId, Type, TypeId, normalise};
12+
use crate::core::{Depth, Name, RowField, RowType, RowTypeId, Type, TypeId, normalise, toolkit};
1313
use crate::error::ErrorKind;
1414
use crate::source::types;
1515
use crate::state::{CheckState, UnificationEntry};
@@ -126,20 +126,40 @@ where
126126
// on both positions; it's impossible to generate any constraint
127127
// dictionaries at this position.
128128
(Type::Function(t1_argument, t1_result), Type::Function(t2_argument, t2_result)) => {
129-
Ok(subtype_with::<NonElaborating, Q>(state, context, t2_argument, t1_argument)?
130-
&& subtype_with::<NonElaborating, Q>(state, context, t1_result, t2_result)?)
129+
subtype_function::<Q>(
130+
state,
131+
context,
132+
(t1_argument, t1_result),
133+
(t2_argument, t2_result),
134+
)
131135
}
132136

133-
// Normalise Type::Function into Type::Application before unification
134-
// This is explained in intern_function_application, it simplifies the
135-
// subtyping rule tremendously vs. pattern matching Type::Application
137+
// Preserve function subtyping on the application representation.
136138
(Type::Application(_, _), Type::Function(t2_argument, t2_result)) => {
137-
let t2 = context.intern_function_application(t2_argument, t2_result);
138-
subtype_with::<P, Q>(state, context, t1, t2)
139+
if let Some((t1_argument, t1_result)) = toolkit::decompose_function(state, context, t1)?
140+
{
141+
subtype_function::<Q>(
142+
state,
143+
context,
144+
(t1_argument, t1_result),
145+
(t2_argument, t2_result),
146+
)
147+
} else {
148+
unify(state, context, t1, t2)
149+
}
139150
}
140151
(Type::Function(t1_argument, t1_result), Type::Application(_, _)) => {
141-
let t1 = context.intern_function_application(t1_argument, t1_result);
142-
subtype_with::<P, Q>(state, context, t1, t2)
152+
if let Some((t2_argument, t2_result)) = toolkit::decompose_function(state, context, t2)?
153+
{
154+
subtype_function::<Q>(
155+
state,
156+
context,
157+
(t1_argument, t1_result),
158+
(t2_argument, t2_result),
159+
)
160+
} else {
161+
unify(state, context, t1, t2)
162+
}
143163
}
144164

145165
// Forall-R
@@ -225,6 +245,21 @@ where
225245
}
226246
}
227247

248+
fn subtype_function<Q>(
249+
state: &mut CheckState,
250+
context: &CheckContext<Q>,
251+
t1: (TypeId, TypeId),
252+
t2: (TypeId, TypeId),
253+
) -> QueryResult<bool>
254+
where
255+
Q: ExternalQueries,
256+
{
257+
let (t1_argument, t1_result) = t1;
258+
let (t2_argument, t2_result) = t2;
259+
Ok(subtype_with::<NonElaborating, Q>(state, context, t2_argument, t1_argument)?
260+
&& subtype_with::<NonElaborating, Q>(state, context, t1_result, t2_result)?)
261+
}
262+
228263
pub fn unify<Q>(
229264
state: &mut CheckState,
230265
context: &CheckContext<Q>,

tests-integration/fixtures/checking2/260_hidden_forall_compose_application_subtype/Main.snap

Lines changed: 0 additions & 27 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)