mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 13:59:08 +00:00
Merge pull request #6128 from roc-lang/debug-auto-opaque
Make sure late specializations of opaques inherit Inspect as needed
This commit is contained in:
commit
a56d7adc17
5 changed files with 285 additions and 90 deletions
|
@ -4662,7 +4662,9 @@ pub fn add_imports(
|
|||
|
||||
let mut cached_symbol_vars = VecMap::default();
|
||||
|
||||
for &symbol in &exposed_for_module.imported_values {
|
||||
let imported_values = exposed_for_module.imported_values.iter().copied();
|
||||
|
||||
for symbol in imported_values {
|
||||
import_variable_for_symbol(
|
||||
subs,
|
||||
constraints,
|
||||
|
|
|
@ -723,23 +723,29 @@ fn get_specialization_lambda_set_ambient_function<P: Phase>(
|
|||
phase: &P,
|
||||
ability_member: Symbol,
|
||||
lset_region: u8,
|
||||
specialization_key: SpecializationTypeKey,
|
||||
mut specialization_key: SpecializationTypeKey,
|
||||
target_rank: Rank,
|
||||
) -> Result<Variable, ()> {
|
||||
loop {
|
||||
match specialization_key {
|
||||
SpecializationTypeKey::Opaque(opaque) => {
|
||||
let opaque_home = opaque.module_id();
|
||||
let external_specialized_lset =
|
||||
phase.with_module_abilities_store(opaque_home, |abilities_store| {
|
||||
let impl_key = roc_can::abilities::ImplKey {
|
||||
let found = phase.with_module_abilities_store(opaque_home, |abilities_store| {
|
||||
find_opaque_specialization_ambient_function(
|
||||
abilities_store,
|
||||
opaque,
|
||||
ability_member,
|
||||
};
|
||||
lset_region,
|
||||
)
|
||||
});
|
||||
|
||||
let opt_specialization =
|
||||
abilities_store.get_implementation(impl_key);
|
||||
match opt_specialization {
|
||||
None => {
|
||||
let external_specialized_lset = match found {
|
||||
FoundOpaqueSpecialization::UpdatedSpecializationKey(key) => {
|
||||
specialization_key = key;
|
||||
continue;
|
||||
}
|
||||
FoundOpaqueSpecialization::AmbientFunction(lset) => lset,
|
||||
FoundOpaqueSpecialization::NotFound => {
|
||||
if P::IS_LATE {
|
||||
internal_error!(
|
||||
"expected to know a specialization for {:?}#{:?}, but it wasn't found",
|
||||
|
@ -747,25 +753,11 @@ fn get_specialization_lambda_set_ambient_function<P: Phase>(
|
|||
ability_member
|
||||
);
|
||||
} else {
|
||||
// doesn't specialize, we'll have reported an error for this
|
||||
Err(())
|
||||
// We'll have reported an error for this.
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
Some(member_impl) => match member_impl {
|
||||
MemberImpl::Impl(spec_symbol) => {
|
||||
let specialization =
|
||||
abilities_store.specialization_info(*spec_symbol).expect("expected custom implementations to always have complete specialization info by this point");
|
||||
|
||||
let specialized_lambda_set = *specialization
|
||||
.specialization_lambda_sets
|
||||
.get(&lset_region)
|
||||
.unwrap_or_else(|| panic!("lambda set region not resolved: {:?}", (spec_symbol, specialization)));
|
||||
Ok(specialized_lambda_set)
|
||||
}
|
||||
MemberImpl::Error => todo_abilities!(),
|
||||
},
|
||||
}
|
||||
})?;
|
||||
};
|
||||
|
||||
let specialized_ambient = phase.copy_lambda_set_ambient_function_to_home_subs(
|
||||
external_specialized_lset,
|
||||
|
@ -773,7 +765,7 @@ fn get_specialization_lambda_set_ambient_function<P: Phase>(
|
|||
subs,
|
||||
);
|
||||
|
||||
Ok(specialized_ambient)
|
||||
return Ok(specialized_ambient);
|
||||
}
|
||||
|
||||
SpecializationTypeKey::Derived(derive_key) => {
|
||||
|
@ -792,7 +784,7 @@ fn get_specialization_lambda_set_ambient_function<P: Phase>(
|
|||
target_rank,
|
||||
);
|
||||
|
||||
Ok(specialized_ambient)
|
||||
return Ok(specialized_ambient);
|
||||
}
|
||||
|
||||
SpecializationTypeKey::Immediate(imm) => {
|
||||
|
@ -808,7 +800,7 @@ fn get_specialization_lambda_set_ambient_function<P: Phase>(
|
|||
let immediate_lambda_set_at_region =
|
||||
phase.get_and_copy_ability_member_ambient_function(imm, lset_region, subs);
|
||||
|
||||
Ok(immediate_lambda_set_at_region)
|
||||
return Ok(immediate_lambda_set_at_region);
|
||||
}
|
||||
|
||||
SpecializationTypeKey::SingleLambdaSetImmediate(imm) => {
|
||||
|
@ -831,7 +823,55 @@ fn get_specialization_lambda_set_ambient_function<P: Phase>(
|
|||
|
||||
roc_types::subs::instantiate_rigids(subs, imported.variable);
|
||||
|
||||
Ok(imported.variable)
|
||||
return Ok(imported.variable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum FoundOpaqueSpecialization {
|
||||
UpdatedSpecializationKey(SpecializationTypeKey),
|
||||
AmbientFunction(Variable),
|
||||
NotFound,
|
||||
}
|
||||
|
||||
fn find_opaque_specialization_ambient_function(
|
||||
abilities_store: &AbilitiesStore,
|
||||
opaque: Symbol,
|
||||
ability_member: Symbol,
|
||||
lset_region: u8,
|
||||
) -> FoundOpaqueSpecialization {
|
||||
let impl_key = roc_can::abilities::ImplKey {
|
||||
opaque,
|
||||
ability_member,
|
||||
};
|
||||
|
||||
let opt_specialization = abilities_store.get_implementation(impl_key);
|
||||
match opt_specialization {
|
||||
None => match ability_member {
|
||||
Symbol::INSPECT_TO_INSPECTOR => FoundOpaqueSpecialization::UpdatedSpecializationKey(
|
||||
SpecializationTypeKey::Immediate(Symbol::INSPECT_OPAQUE),
|
||||
),
|
||||
_ => FoundOpaqueSpecialization::NotFound,
|
||||
},
|
||||
Some(member_impl) => match member_impl {
|
||||
MemberImpl::Impl(spec_symbol) => {
|
||||
let specialization =
|
||||
abilities_store.specialization_info(*spec_symbol).expect("expected custom implementations to always have complete specialization info by this point");
|
||||
|
||||
let specialized_lambda_set = *specialization
|
||||
.specialization_lambda_sets
|
||||
.get(&lset_region)
|
||||
.unwrap_or_else(|| {
|
||||
panic!(
|
||||
"lambda set region not resolved: {:?}",
|
||||
(spec_symbol, specialization)
|
||||
)
|
||||
});
|
||||
|
||||
FoundOpaqueSpecialization::AmbientFunction(specialized_lambda_set)
|
||||
}
|
||||
MemberImpl::Error => todo_abilities!(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2288,4 +2288,42 @@ mod inspect {
|
|||
RocStr
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn opaque_automatic() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
Op := {}
|
||||
|
||||
main = Inspect.toDbgStr (Inspect.inspect (@Op {}))
|
||||
"#
|
||||
),
|
||||
RocStr::from(r#"<opaque>"#),
|
||||
RocStr
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn opaque_automatic_with_polymorphic_call() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
Op := {}
|
||||
|
||||
late = \a -> Inspect.toDbgStr (Inspect.inspect a)
|
||||
|
||||
main = late (@Op {})
|
||||
"#
|
||||
),
|
||||
RocStr::from(r#"<opaque>"#),
|
||||
RocStr
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
# +emit:mono
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
Op := {}
|
||||
|
||||
main =
|
||||
dbg (@Op {})
|
||||
1
|
||||
|
||||
# -emit:mono
|
||||
procedure Inspect.251 (Inspect.252):
|
||||
let Inspect.317 : Str = "<opaque>";
|
||||
let Inspect.316 : Str = CallByName Inspect.61 Inspect.252 Inspect.317;
|
||||
ret Inspect.316;
|
||||
|
||||
procedure Inspect.30 (Inspect.147):
|
||||
ret Inspect.147;
|
||||
|
||||
procedure Inspect.35 (Inspect.300):
|
||||
ret Inspect.300;
|
||||
|
||||
procedure Inspect.36 (Inspect.304):
|
||||
let Inspect.311 : Str = "";
|
||||
ret Inspect.311;
|
||||
|
||||
procedure Inspect.45 (Inspect.302):
|
||||
let Inspect.314 : {} = Struct {};
|
||||
let Inspect.313 : {} = CallByName Inspect.30 Inspect.314;
|
||||
ret Inspect.313;
|
||||
|
||||
procedure Inspect.5 (Inspect.150):
|
||||
let Inspect.312 : {} = CallByName Inspect.45 Inspect.150;
|
||||
let Inspect.309 : {} = Struct {};
|
||||
let Inspect.308 : Str = CallByName Inspect.36 Inspect.309;
|
||||
let Inspect.307 : Str = CallByName Inspect.251 Inspect.308;
|
||||
ret Inspect.307;
|
||||
|
||||
procedure Inspect.61 (Inspect.303, Inspect.298):
|
||||
let Inspect.319 : Str = CallByName Str.3 Inspect.303 Inspect.298;
|
||||
dec Inspect.298;
|
||||
ret Inspect.319;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.292 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.292;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.5 : {} = Struct {};
|
||||
let Test.4 : Str = CallByName Inspect.5 Test.5;
|
||||
let Test.2 : Str = CallByName Inspect.35 Test.4;
|
||||
dbg Test.2;
|
||||
dec Test.2;
|
||||
let Test.3 : I64 = 1i64;
|
||||
ret Test.3;
|
|
@ -0,0 +1,61 @@
|
|||
# +emit:mono
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
Op := {}
|
||||
|
||||
late = \a ->
|
||||
dbg a
|
||||
1
|
||||
|
||||
main =
|
||||
late (@Op {})
|
||||
|
||||
# -emit:mono
|
||||
procedure Inspect.251 (Inspect.252):
|
||||
let Inspect.317 : Str = "<opaque>";
|
||||
let Inspect.316 : Str = CallByName Inspect.61 Inspect.252 Inspect.317;
|
||||
ret Inspect.316;
|
||||
|
||||
procedure Inspect.30 (Inspect.147):
|
||||
ret Inspect.147;
|
||||
|
||||
procedure Inspect.35 (Inspect.300):
|
||||
ret Inspect.300;
|
||||
|
||||
procedure Inspect.36 (Inspect.304):
|
||||
let Inspect.311 : Str = "";
|
||||
ret Inspect.311;
|
||||
|
||||
procedure Inspect.45 (Inspect.302):
|
||||
let Inspect.314 : {} = Struct {};
|
||||
let Inspect.313 : {} = CallByName Inspect.30 Inspect.314;
|
||||
ret Inspect.313;
|
||||
|
||||
procedure Inspect.5 (Inspect.150):
|
||||
let Inspect.312 : {} = CallByName Inspect.45 Inspect.150;
|
||||
let Inspect.309 : {} = Struct {};
|
||||
let Inspect.308 : Str = CallByName Inspect.36 Inspect.309;
|
||||
let Inspect.307 : Str = CallByName Inspect.251 Inspect.308;
|
||||
ret Inspect.307;
|
||||
|
||||
procedure Inspect.61 (Inspect.303, Inspect.298):
|
||||
let Inspect.319 : Str = CallByName Str.3 Inspect.303 Inspect.298;
|
||||
dec Inspect.298;
|
||||
ret Inspect.319;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.292 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.292;
|
||||
|
||||
procedure Test.2 (Test.3):
|
||||
let Test.8 : Str = CallByName Inspect.5 Test.3;
|
||||
let Test.4 : Str = CallByName Inspect.35 Test.8;
|
||||
dbg Test.4;
|
||||
dec Test.4;
|
||||
let Test.7 : I64 = 1i64;
|
||||
ret Test.7;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.6 : {} = Struct {};
|
||||
let Test.5 : I64 = CallByName Test.2 Test.6;
|
||||
ret Test.5;
|
Loading…
Add table
Add a link
Reference in a new issue