mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 08:11:12 +00:00
extract logic for identifiers
This commit is contained in:
parent
aaae923e59
commit
6da37329e7
1 changed files with 79 additions and 67 deletions
|
@ -75,73 +75,9 @@ pub fn canonicalize_pattern<'a>(
|
||||||
|
|
||||||
let can_pattern = match &pattern {
|
let can_pattern = match &pattern {
|
||||||
&Identifier(ref name) => {
|
&Identifier(ref name) => {
|
||||||
let lowercase_ident = Ident::Unqualified((*name).into());
|
match canonicalize_pattern_identifier(name, env, scope, region, shadowable_idents) {
|
||||||
|
Ok(symbol) => Pattern::Identifier(symbol),
|
||||||
// We use shadowable_idents for this, and not scope, because for assignments
|
Err(loc_shadowed_ident) => Pattern::Shadowed(loc_shadowed_ident),
|
||||||
// they are different. When canonicalizing a particular assignment, that new
|
|
||||||
// ident is in scope (for recursion) but not shadowable.
|
|
||||||
//
|
|
||||||
// For example, when canonicalizing (fibonacci = ...), `fibonacci` should be in scope
|
|
||||||
// so that it can refer to itself without getting a naming problem, but it should not
|
|
||||||
// be in the collection of shadowable idents because you can't shadow yourself!
|
|
||||||
match shadowable_idents.get(&lowercase_ident) {
|
|
||||||
Some((_, region)) => {
|
|
||||||
let loc_shadowed_ident = Located {
|
|
||||||
region: *region,
|
|
||||||
value: lowercase_ident,
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is already in scope, meaning it's about to be shadowed.
|
|
||||||
// Shadowing is not allowed!
|
|
||||||
env.problem(Problem::Shadowing(loc_shadowed_ident.clone()));
|
|
||||||
|
|
||||||
// Change this Pattern to a Shadowed variant, so that
|
|
||||||
// codegen knows to generate a runtime exception here.
|
|
||||||
Pattern::Shadowed(loc_shadowed_ident)
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
// Make sure we aren't shadowing something in the home module's scope.
|
|
||||||
let qualified_ident =
|
|
||||||
Ident::Qualified(env.home.clone(), lowercase_ident.name());
|
|
||||||
|
|
||||||
match scope.idents.get(&qualified_ident) {
|
|
||||||
Some((_, region)) => {
|
|
||||||
let loc_shadowed_ident = Located {
|
|
||||||
region: *region,
|
|
||||||
value: qualified_ident,
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is already in scope, meaning it's about to be shadowed.
|
|
||||||
// Shadowing is not allowed!
|
|
||||||
env.problem(Problem::Shadowing(loc_shadowed_ident.clone()));
|
|
||||||
|
|
||||||
// Change this Pattern to a Shadowed variant, so that
|
|
||||||
// codegen knows to generate a runtime exception here.
|
|
||||||
Pattern::Shadowed(loc_shadowed_ident)
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
let new_ident = qualified_ident.clone();
|
|
||||||
let new_name = qualified_ident.name();
|
|
||||||
let symbol = scope.symbol(&new_name);
|
|
||||||
|
|
||||||
// This is a fresh identifier that wasn't already in scope.
|
|
||||||
// Add it to scope!
|
|
||||||
let symbol_and_region = (symbol.clone(), region);
|
|
||||||
|
|
||||||
// Add this to both scope.idents *and* shadowable_idents.
|
|
||||||
// The latter is relevant when recursively canonicalizing
|
|
||||||
// tag application patterns, which can bring multiple
|
|
||||||
// new idents into scope. For example, it's important that
|
|
||||||
// we catch (Blah foo foo) -> … as being an example of shadowing.
|
|
||||||
scope
|
|
||||||
.idents
|
|
||||||
.insert(new_ident.clone(), symbol_and_region.clone());
|
|
||||||
shadowable_idents.insert(new_ident, symbol_and_region);
|
|
||||||
|
|
||||||
Pattern::Identifier(symbol)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&GlobalTag(name) => {
|
&GlobalTag(name) => {
|
||||||
|
@ -247,6 +183,82 @@ pub fn canonicalize_pattern<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn canonicalize_pattern_identifier<'a>(
|
||||||
|
name: &'a &str,
|
||||||
|
env: &'a mut Env,
|
||||||
|
scope: &mut Scope,
|
||||||
|
region: Region,
|
||||||
|
shadowable_idents: &'a mut ImMap<Ident, (Symbol, Region)>,
|
||||||
|
) -> Result<Symbol, Located<Ident>> {
|
||||||
|
let lowercase_ident = Ident::Unqualified((*name).into());
|
||||||
|
|
||||||
|
// We use shadowable_idents for this, and not scope, because for assignments
|
||||||
|
// they are different. When canonicalizing a particular assignment, that new
|
||||||
|
// ident is in scope (for recursion) but not shadowable.
|
||||||
|
//
|
||||||
|
// For example, when canonicalizing (fibonacci = ...), `fibonacci` should be in scope
|
||||||
|
// so that it can refer to itself without getting a naming problem, but it should not
|
||||||
|
// be in the collection of shadowable idents because you can't shadow yourself!
|
||||||
|
match shadowable_idents.get(&lowercase_ident) {
|
||||||
|
Some((_, region)) => {
|
||||||
|
let loc_shadowed_ident = Located {
|
||||||
|
region: *region,
|
||||||
|
value: lowercase_ident,
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is already in scope, meaning it's about to be shadowed.
|
||||||
|
// Shadowing is not allowed!
|
||||||
|
env.problem(Problem::Shadowing(loc_shadowed_ident.clone()));
|
||||||
|
|
||||||
|
// Change this Pattern to a Shadowed variant, so that
|
||||||
|
// codegen knows to generate a runtime exception here.
|
||||||
|
Err(loc_shadowed_ident)
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
// Make sure we aren't shadowing something in the home module's scope.
|
||||||
|
let qualified_ident = Ident::Qualified(env.home.clone(), lowercase_ident.name());
|
||||||
|
|
||||||
|
match scope.idents.get(&qualified_ident) {
|
||||||
|
Some((_, region)) => {
|
||||||
|
let loc_shadowed_ident = Located {
|
||||||
|
region: *region,
|
||||||
|
value: qualified_ident,
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is already in scope, meaning it's about to be shadowed.
|
||||||
|
// Shadowing is not allowed!
|
||||||
|
env.problem(Problem::Shadowing(loc_shadowed_ident.clone()));
|
||||||
|
|
||||||
|
// Change this Pattern to a Shadowed variant, so that
|
||||||
|
// codegen knows to generate a runtime exception here.
|
||||||
|
Err(loc_shadowed_ident)
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let new_ident = qualified_ident.clone();
|
||||||
|
let new_name = qualified_ident.name();
|
||||||
|
let symbol = scope.symbol(&new_name);
|
||||||
|
|
||||||
|
// This is a fresh identifier that wasn't already in scope.
|
||||||
|
// Add it to scope!
|
||||||
|
let symbol_and_region = (symbol.clone(), region);
|
||||||
|
|
||||||
|
// Add this to both scope.idents *and* shadowable_idents.
|
||||||
|
// The latter is relevant when recursively canonicalizing
|
||||||
|
// tag application patterns, which can bring multiple
|
||||||
|
// new idents into scope. For example, it's important that
|
||||||
|
// we catch (Blah foo foo) -> … as being an example of shadowing.
|
||||||
|
scope
|
||||||
|
.idents
|
||||||
|
.insert(new_ident.clone(), symbol_and_region.clone());
|
||||||
|
shadowable_idents.insert(new_ident, symbol_and_region);
|
||||||
|
|
||||||
|
Ok(symbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// When we detect an unsupported pattern type (e.g. 5 = 1 + 2 is unsupported because you can't
|
/// When we detect an unsupported pattern type (e.g. 5 = 1 + 2 is unsupported because you can't
|
||||||
/// assign to Int patterns), report it to Env and return an UnsupportedPattern runtime error pattern.
|
/// assign to Int patterns), report it to Env and return an UnsupportedPattern runtime error pattern.
|
||||||
fn unsupported_pattern(env: &mut Env, pattern_type: PatternType, region: Region) -> Pattern {
|
fn unsupported_pattern(env: &mut Env, pattern_type: PatternType, region: Region) -> Pattern {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue