[core] typecheck: Disallow redeclaration of var shadowing global

This commit is contained in:
David Mak 2024-10-05 17:08:46 +08:00
parent b538611cb0
commit 3afe69fcda
1 changed files with 16 additions and 2 deletions

View File

@ -34,6 +34,20 @@ impl<'a> Inferencer<'a> {
Err(HashSet::from([format!("cannot assign to a `none` (at {})", pattern.location)])) Err(HashSet::from([format!("cannot assign to a `none` (at {})", pattern.location)]))
} }
ExprKind::Name { id, .. } => { ExprKind::Name { id, .. } => {
// If `id` refers to a declared symbol, reject this assignment if it is used in the
// context of an (implicit) global variable
if let Some(id_info) = self.defined_identifiers.get(id) {
if matches!(
id_info.source,
DeclarationSource::Global { is_explicit: Some(false) }
) {
return Err(HashSet::from([format!(
"cannot access local variable '{id}' before it is declared (at {})",
pattern.location
)]));
}
}
if !defined_identifiers.contains_key(id) { if !defined_identifiers.contains_key(id) {
defined_identifiers.insert(*id, IdentifierInfo::default()); defined_identifiers.insert(*id, IdentifierInfo::default());
} }
@ -104,7 +118,7 @@ impl<'a> Inferencer<'a> {
*id, *id,
) { ) {
Ok(_) => { Ok(_) => {
self.defined_identifiers.insert(*id, IdentifierInfo::default()); defined_identifiers.insert(*id, IdentifierInfo::default());
} }
Err(e) => { Err(e) => {
return Err(HashSet::from([format!( return Err(HashSet::from([format!(
@ -370,7 +384,7 @@ impl<'a> Inferencer<'a> {
if let Some(id_info) = defined_identifiers.get(id) { if let Some(id_info) = defined_identifiers.get(id) {
if id_info.source == DeclarationSource::Local { if id_info.source == DeclarationSource::Local {
return Err(HashSet::from([format!( return Err(HashSet::from([format!(
"name '{id}' is assigned to before global declaration at {}", "name '{id}' is used prior to global declaration at {}",
stmt.location, stmt.location,
)])); )]));
} }