track exactly when we introduce a symbol in a let-block

This commit is contained in:
Folkert 2022-04-23 23:00:20 +02:00
parent ca072b6625
commit 1f824f3664
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C

View file

@ -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 {