mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 08:11:12 +00:00
track exactly when we introduce a symbol in a let-block
This commit is contained in:
parent
ca072b6625
commit
1f824f3664
1 changed files with 69 additions and 29 deletions
|
@ -110,12 +110,39 @@ enum PendingTypeDef<'a> {
|
||||||
/// An invalid alias, that is ignored in the rest of the pipeline
|
/// An invalid alias, that is ignored in the rest of the pipeline
|
||||||
/// e.g. a shadowed alias, or a definition like `MyAlias 1 : Int`
|
/// e.g. a shadowed alias, or a definition like `MyAlias 1 : Int`
|
||||||
/// with an incorrect pattern
|
/// with an incorrect pattern
|
||||||
#[allow(dead_code)]
|
InvalidAlias {
|
||||||
InvalidAlias { kind: AliasKind },
|
#[allow(dead_code)]
|
||||||
|
kind: AliasKind,
|
||||||
|
symbol: Symbol,
|
||||||
|
region: Region,
|
||||||
|
},
|
||||||
|
|
||||||
/// An invalid ability, that is ignored in the rest of the pipeline.
|
/// An invalid ability, that is ignored in the rest of the pipeline.
|
||||||
/// E.g. a shadowed ability, or with a bad definition.
|
/// E.g. a shadowed ability, or with a bad definition.
|
||||||
InvalidAbility,
|
InvalidAbility {
|
||||||
|
symbol: Symbol,
|
||||||
|
region: Region,
|
||||||
|
},
|
||||||
|
|
||||||
|
AbilityNotOnToplevel,
|
||||||
|
AbilityShadows,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PendingTypeDef<'_> {
|
||||||
|
fn introduction(&self) -> Option<(Symbol, Region)> {
|
||||||
|
match self {
|
||||||
|
PendingTypeDef::Alias { name, ann, .. } => {
|
||||||
|
let region = Region::span_across(&name.region, &ann.region);
|
||||||
|
|
||||||
|
Some((name.value, region))
|
||||||
|
}
|
||||||
|
PendingTypeDef::Ability { name, .. } => Some((name.value, name.region)),
|
||||||
|
PendingTypeDef::InvalidAlias { symbol, region, .. } => Some((*symbol, *region)),
|
||||||
|
PendingTypeDef::InvalidAbility { symbol, region } => Some((*symbol, *region)),
|
||||||
|
PendingTypeDef::AbilityNotOnToplevel => None,
|
||||||
|
PendingTypeDef::AbilityShadows => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// See github.com/rtfeldman/roc/issues/800 for discussion of the large_enum_variant check.
|
// See github.com/rtfeldman/roc/issues/800 for discussion of the large_enum_variant check.
|
||||||
|
@ -280,7 +307,14 @@ pub(crate) fn canonicalize_defs<'a>(
|
||||||
|
|
||||||
let mut referenced_type_symbols = MutMap::default();
|
let mut referenced_type_symbols = MutMap::default();
|
||||||
|
|
||||||
|
// Determine which idents we introduced in the course of this process.
|
||||||
|
let mut symbols_introduced = MutMap::default();
|
||||||
|
|
||||||
for pending_def in pending_type_defs.into_iter() {
|
for pending_def in pending_type_defs.into_iter() {
|
||||||
|
if let Some((symbol, region)) = pending_def.introduction() {
|
||||||
|
symbols_introduced.insert(symbol, region);
|
||||||
|
}
|
||||||
|
|
||||||
match pending_def {
|
match pending_def {
|
||||||
PendingTypeDef::Alias {
|
PendingTypeDef::Alias {
|
||||||
name,
|
name,
|
||||||
|
@ -316,14 +350,13 @@ pub(crate) fn canonicalize_defs<'a>(
|
||||||
type_defs.insert(name.value, TypeDef::Ability(name, members));
|
type_defs.insert(name.value, TypeDef::Ability(name, members));
|
||||||
abilities_in_scope.push(name.value);
|
abilities_in_scope.push(name.value);
|
||||||
}
|
}
|
||||||
PendingTypeDef::InvalidAlias { .. } | PendingTypeDef::InvalidAbility { .. } => { /* ignore */
|
PendingTypeDef::InvalidAlias { .. }
|
||||||
}
|
| PendingTypeDef::InvalidAbility { .. }
|
||||||
|
| PendingTypeDef::AbilityShadows
|
||||||
|
| PendingTypeDef::AbilityNotOnToplevel => { /* ignore */ }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine which idents we introduced in the course of this process.
|
|
||||||
let mut symbols_introduced = MutMap::default();
|
|
||||||
|
|
||||||
let sorted = sort_type_defs_before_introduction(referenced_type_symbols);
|
let sorted = sort_type_defs_before_introduction(referenced_type_symbols);
|
||||||
let mut aliases = SendMap::default();
|
let mut aliases = SendMap::default();
|
||||||
let mut abilities = MutMap::default();
|
let mut abilities = MutMap::default();
|
||||||
|
@ -331,8 +364,6 @@ pub(crate) fn canonicalize_defs<'a>(
|
||||||
for type_name in sorted {
|
for type_name in sorted {
|
||||||
match type_defs.remove(&type_name).unwrap() {
|
match type_defs.remove(&type_name).unwrap() {
|
||||||
TypeDef::AliasLike(name, vars, ann, kind) => {
|
TypeDef::AliasLike(name, vars, ann, kind) => {
|
||||||
symbols_introduced.insert(name.value, name.region);
|
|
||||||
|
|
||||||
let symbol = name.value;
|
let symbol = name.value;
|
||||||
let can_ann = canonicalize_annotation(
|
let can_ann = canonicalize_annotation(
|
||||||
env,
|
env,
|
||||||
|
@ -433,8 +464,6 @@ pub(crate) fn canonicalize_defs<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeDef::Ability(name, members) => {
|
TypeDef::Ability(name, members) => {
|
||||||
symbols_introduced.insert(name.value, name.region);
|
|
||||||
|
|
||||||
// For now we enforce that aliases cannot reference abilities, so let's wait to
|
// For now we enforce that aliases cannot reference abilities, so let's wait to
|
||||||
// resolve ability definitions until aliases are resolved and in scope below.
|
// resolve ability definitions until aliases are resolved and in scope below.
|
||||||
abilities.insert(name.value, (name, members));
|
abilities.insert(name.value, (name, members));
|
||||||
|
@ -461,6 +490,7 @@ pub(crate) fn canonicalize_defs<'a>(
|
||||||
&mut output,
|
&mut output,
|
||||||
var_store,
|
var_store,
|
||||||
&mut scope,
|
&mut scope,
|
||||||
|
&mut symbols_introduced,
|
||||||
abilities,
|
abilities,
|
||||||
&abilities_in_scope,
|
&abilities_in_scope,
|
||||||
pattern_type,
|
pattern_type,
|
||||||
|
@ -535,14 +565,6 @@ pub(crate) fn canonicalize_defs<'a>(
|
||||||
def_ordering.insert_symbol_references(def_id as u32, &temp_output.references)
|
def_ordering.insert_symbol_references(def_id as u32, &temp_output.references)
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is now mostly responsible for adding type names and ability members
|
|
||||||
// see if we can do this in a more efficient way
|
|
||||||
for (symbol, region) in scope.symbols() {
|
|
||||||
if !original_scope.contains_symbol(*symbol) {
|
|
||||||
symbols_introduced.insert(*symbol, *region);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This returns both the defs info as well as the new scope.
|
// This returns both the defs info as well as the new scope.
|
||||||
//
|
//
|
||||||
// We have to return the new scope because we added defs to it
|
// We have to return the new scope because we added defs to it
|
||||||
|
@ -550,9 +572,6 @@ pub(crate) fn canonicalize_defs<'a>(
|
||||||
// the return expr), but we didn't want to mutate the original scope
|
// the return expr), but we didn't want to mutate the original scope
|
||||||
// directly because we wanted to keep a clone of it around to diff
|
// directly because we wanted to keep a clone of it around to diff
|
||||||
// when looking for unused idents.
|
// when looking for unused idents.
|
||||||
//
|
|
||||||
// We have to return the scope separately from the defs, because the
|
|
||||||
// defs need to get moved later.
|
|
||||||
(
|
(
|
||||||
CanDefs {
|
CanDefs {
|
||||||
defs,
|
defs,
|
||||||
|
@ -567,11 +586,13 @@ pub(crate) fn canonicalize_defs<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolve all pending abilities, to add them to scope.
|
/// Resolve all pending abilities, to add them to scope.
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn resolve_abilities<'a>(
|
fn resolve_abilities<'a>(
|
||||||
env: &mut Env<'a>,
|
env: &mut Env<'a>,
|
||||||
output: &mut Output,
|
output: &mut Output,
|
||||||
var_store: &mut VarStore,
|
var_store: &mut VarStore,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
|
symbols_introduced: &mut MutMap<Symbol, Region>,
|
||||||
abilities: MutMap<Symbol, (Loc<Symbol>, &[AbilityMember])>,
|
abilities: MutMap<Symbol, (Loc<Symbol>, &[AbilityMember])>,
|
||||||
abilities_in_scope: &[Symbol],
|
abilities_in_scope: &[Symbol],
|
||||||
pattern_type: PatternType,
|
pattern_type: PatternType,
|
||||||
|
@ -615,6 +636,8 @@ fn resolve_abilities<'a>(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
symbols_introduced.insert(member_sym, name_region);
|
||||||
|
|
||||||
if pattern_type == PatternType::TopLevelDef {
|
if pattern_type == PatternType::TopLevelDef {
|
||||||
env.top_level_symbols.insert(member_sym);
|
env.top_level_symbols.insert(member_sym);
|
||||||
}
|
}
|
||||||
|
@ -1692,7 +1715,11 @@ fn to_pending_type_def<'a>(
|
||||||
|
|
||||||
return Some((
|
return Some((
|
||||||
Output::default(),
|
Output::default(),
|
||||||
PendingTypeDef::InvalidAlias { kind },
|
PendingTypeDef::InvalidAlias {
|
||||||
|
kind,
|
||||||
|
symbol,
|
||||||
|
region,
|
||||||
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1713,14 +1740,21 @@ fn to_pending_type_def<'a>(
|
||||||
Some((Output::default(), pending_def))
|
Some((Output::default(), pending_def))
|
||||||
}
|
}
|
||||||
|
|
||||||
Err((original_region, loc_shadowed_symbol, _new_symbol)) => {
|
Err((original_region, loc_shadowed_symbol, new_symbol)) => {
|
||||||
env.problem(Problem::Shadowing {
|
env.problem(Problem::Shadowing {
|
||||||
original_region,
|
original_region,
|
||||||
shadow: loc_shadowed_symbol,
|
shadow: loc_shadowed_symbol,
|
||||||
kind: shadow_kind,
|
kind: shadow_kind,
|
||||||
});
|
});
|
||||||
|
|
||||||
Some((Output::default(), PendingTypeDef::InvalidAlias { kind }))
|
Some((
|
||||||
|
Output::default(),
|
||||||
|
PendingTypeDef::InvalidAlias {
|
||||||
|
kind,
|
||||||
|
symbol: new_symbol,
|
||||||
|
region,
|
||||||
|
},
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1735,7 +1769,7 @@ fn to_pending_type_def<'a>(
|
||||||
);
|
);
|
||||||
env.problem(Problem::AbilityNotOnToplevel { region });
|
env.problem(Problem::AbilityNotOnToplevel { region });
|
||||||
|
|
||||||
Some((Output::default(), PendingTypeDef::InvalidAbility))
|
Some((Output::default(), PendingTypeDef::AbilityNotOnToplevel))
|
||||||
}
|
}
|
||||||
|
|
||||||
Ability {
|
Ability {
|
||||||
|
@ -1756,7 +1790,7 @@ fn to_pending_type_def<'a>(
|
||||||
shadow: shadowed_symbol,
|
shadow: shadowed_symbol,
|
||||||
kind: ShadowKind::Ability,
|
kind: ShadowKind::Ability,
|
||||||
});
|
});
|
||||||
return Some((Output::default(), PendingTypeDef::InvalidAbility));
|
return Some((Output::default(), PendingTypeDef::AbilityShadows));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1768,7 +1802,13 @@ fn to_pending_type_def<'a>(
|
||||||
name: name.value,
|
name: name.value,
|
||||||
variables_region,
|
variables_region,
|
||||||
});
|
});
|
||||||
return Some((Output::default(), PendingTypeDef::InvalidAbility));
|
return Some((
|
||||||
|
Output::default(),
|
||||||
|
PendingTypeDef::InvalidAbility {
|
||||||
|
symbol: name.value,
|
||||||
|
region: name.region,
|
||||||
|
},
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let pending_ability = PendingTypeDef::Ability {
|
let pending_ability = PendingTypeDef::Ability {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue