mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 19:58:18 +00:00
Report specializations that target the unexpected type
This commit is contained in:
parent
968bd468a8
commit
3703940da9
3 changed files with 111 additions and 28 deletions
|
@ -110,6 +110,12 @@ pub enum TypeError {
|
|||
derive_region: Region,
|
||||
impl_region: Region,
|
||||
},
|
||||
WrongSpecialization {
|
||||
region: Region,
|
||||
ability_member: Symbol,
|
||||
expected_opaque: Symbol,
|
||||
found_opaque: Symbol,
|
||||
},
|
||||
}
|
||||
|
||||
use roc_types::types::Alias;
|
||||
|
@ -1739,39 +1745,60 @@ fn check_ability_specialization(
|
|||
|
||||
match specialization_type {
|
||||
Some(Obligated::Opaque(opaque)) => {
|
||||
// This is a specialization for an opaque - that's allowed.
|
||||
// This is a specialization for an opaque - but is it the opaque the
|
||||
// specialization was claimed to be for?
|
||||
if opaque == impl_key.opaque {
|
||||
// It was! All is good.
|
||||
|
||||
subs.commit_snapshot(snapshot);
|
||||
introduce(subs, rank, pools, &vars);
|
||||
subs.commit_snapshot(snapshot);
|
||||
introduce(subs, rank, pools, &vars);
|
||||
|
||||
let specialization_lambda_sets = specialization_lambda_sets
|
||||
.into_iter()
|
||||
.map(|((symbol, region), var)| {
|
||||
debug_assert_eq!(symbol, ability_member);
|
||||
(region, var)
|
||||
})
|
||||
.collect();
|
||||
let specialization_lambda_sets = specialization_lambda_sets
|
||||
.into_iter()
|
||||
.map(|((symbol, region), var)| {
|
||||
debug_assert_eq!(symbol, ability_member);
|
||||
(region, var)
|
||||
})
|
||||
.collect();
|
||||
|
||||
deferred_uls_to_resolve.union(other_lambda_sets_to_specialize);
|
||||
deferred_uls_to_resolve.union(other_lambda_sets_to_specialize);
|
||||
|
||||
let specialization_region = symbol_loc_var.region;
|
||||
let specialization =
|
||||
MemberSpecializationInfo::new(symbol, specialization_lambda_sets);
|
||||
let specialization_region = symbol_loc_var.region;
|
||||
let specialization =
|
||||
MemberSpecializationInfo::new(symbol, specialization_lambda_sets);
|
||||
|
||||
// Make sure we check that the opaque has specialized all members of the
|
||||
// ability, after we finish solving the module.
|
||||
deferred_obligations
|
||||
.add(must_implement_ability, AbilityImplError::IncompleteAbility);
|
||||
// This specialization dominates any derives that might be present.
|
||||
deferred_obligations.dominate(
|
||||
RequestedDeriveKey {
|
||||
opaque,
|
||||
ability: parent_ability,
|
||||
},
|
||||
specialization_region,
|
||||
);
|
||||
// Make sure we check that the opaque has specialized all members of the
|
||||
// ability, after we finish solving the module.
|
||||
deferred_obligations
|
||||
.add(must_implement_ability, AbilityImplError::IncompleteAbility);
|
||||
// This specialization dominates any derives that might be present.
|
||||
deferred_obligations.dominate(
|
||||
RequestedDeriveKey {
|
||||
opaque,
|
||||
ability: parent_ability,
|
||||
},
|
||||
specialization_region,
|
||||
);
|
||||
|
||||
Ok(specialization)
|
||||
Ok(specialization)
|
||||
} else {
|
||||
// This def is not specialized for the claimed opaque type, that's an
|
||||
// error.
|
||||
|
||||
// Commit so that `var` persists in subs.
|
||||
subs.commit_snapshot(snapshot);
|
||||
|
||||
let problem = TypeError::WrongSpecialization {
|
||||
region: symbol_loc_var.region,
|
||||
ability_member: impl_key.ability_member,
|
||||
expected_opaque: impl_key.opaque,
|
||||
found_opaque: opaque,
|
||||
};
|
||||
|
||||
problems.push(problem);
|
||||
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
Some(Obligated::Adhoc(var)) => {
|
||||
// This is a specialization of a structural type - never allowed.
|
||||
|
@ -1795,7 +1822,7 @@ fn check_ability_specialization(
|
|||
None => {
|
||||
// This can happen when every ability constriant on a type variable went
|
||||
// through only another type variable. That means this def is not specialized
|
||||
// for one concrete type - we won't admit this.
|
||||
// for one concrete type, and especially not our opaque - we won't admit this currently.
|
||||
|
||||
// Rollback the snapshot so we unlink the root signature with the specialization,
|
||||
// so we can have two separate error types.
|
||||
|
|
|
@ -254,6 +254,35 @@ pub fn type_problem<'b>(
|
|||
severity: Severity::Warning,
|
||||
})
|
||||
}
|
||||
WrongSpecialization {
|
||||
region,
|
||||
ability_member,
|
||||
expected_opaque,
|
||||
found_opaque,
|
||||
} => {
|
||||
let stack = [
|
||||
alloc.concat([
|
||||
alloc.reflow("This specialization of "),
|
||||
alloc.symbol_unqualified(ability_member),
|
||||
alloc.reflow(" is not for the expected type:"),
|
||||
]),
|
||||
alloc.region(lines.convert_region(region)),
|
||||
alloc.concat([
|
||||
alloc.reflow("It was previously claimed to be a specialization for "),
|
||||
alloc.symbol_unqualified(expected_opaque),
|
||||
alloc.reflow(", but was determined to actually specialize "),
|
||||
alloc.symbol_unqualified(found_opaque),
|
||||
alloc.reflow("!"),
|
||||
]),
|
||||
];
|
||||
|
||||
Some(Report {
|
||||
title: "WRONG SPECIALIZATION TYPE".to_string(),
|
||||
filename,
|
||||
doc: alloc.stack(stack),
|
||||
severity: Severity::RuntimeError,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10089,4 +10089,31 @@ All branches in an `if` must have the same type!
|
|||
your code don't wonder why it is there.
|
||||
"###
|
||||
);
|
||||
|
||||
test_report!(
|
||||
specialization_for_wrong_type,
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" provides [hash, Id, Id2] to "./platform"
|
||||
|
||||
Hash has hash : a -> U64 | a has Hash
|
||||
|
||||
Id := {} has [Hash {hash}]
|
||||
Id2 := {}
|
||||
|
||||
hash = \@Id2 _ -> 0
|
||||
"#
|
||||
),
|
||||
@r###"
|
||||
── WRONG SPECIALIZATION TYPE ───────────────────────────── /code/proj/Main.roc ─
|
||||
|
||||
This specialization of `hash` is not for the expected type:
|
||||
|
||||
8│ hash = \@Id2 _ -> 0
|
||||
^^^^
|
||||
|
||||
It was previously claimed to be a specialization for `Id`, but was
|
||||
determined to actually specialize `Id2`!
|
||||
"###
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue