[core] typecheck/type_inferencer: Differentiate global symbols

Required for analyzing use of global symbols before global declaration.
This commit is contained in:
David Mak 2024-10-05 15:57:51 +08:00
parent 1a197c67f6
commit 51bf126a32
2 changed files with 30 additions and 6 deletions

View File

@ -10,7 +10,7 @@ use nac3parser::ast::{
};
use super::{
type_inferencer::{IdentifierInfo, Inferencer},
type_inferencer::{DeclarationSource, IdentifierInfo, Inferencer},
typedef::{Type, TypeEnum},
};
use crate::toplevel::helper::PrimDef;
@ -368,7 +368,7 @@ impl<'a> Inferencer<'a> {
StmtKind::Global { names, .. } => {
for id in names {
if let Some(id_info) = defined_identifiers.get(id) {
if !id_info.is_global {
if id_info.source == DeclarationSource::Local {
return Err(HashSet::from([format!(
"name '{id}' is assigned to before global declaration at {}",
stmt.location,
@ -385,8 +385,12 @@ impl<'a> Inferencer<'a> {
*id,
) {
Ok(_) => {
self.defined_identifiers
.insert(*id, IdentifierInfo { is_global: true });
self.defined_identifiers.insert(
*id,
IdentifierInfo {
source: DeclarationSource::Global { is_explicit: Some(true) },
},
);
}
Err(e) => {
return Err(HashSet::from([format!(

View File

@ -88,11 +88,31 @@ impl PrimitiveStore {
}
}
/// The location where an identifier declaration refers to.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum DeclarationSource {
/// Local scope.
Local,
/// Global scope.
Global {
/// Whether the identifier is declared by the use of `global` statement. This field is
/// [`None`] if the identifier does not refer to a variable.
is_explicit: Option<bool>,
},
}
/// Information regarding a defined identifier.
#[derive(Clone, Copy, Debug, Default)]
#[derive(Clone, Copy, Debug)]
pub struct IdentifierInfo {
/// Whether this identifier refers to a global variable.
pub is_global: bool,
pub source: DeclarationSource,
}
impl Default for IdentifierInfo {
fn default() -> Self {
IdentifierInfo { source: DeclarationSource::Local }
}
}
impl IdentifierInfo {