Qualified lookups return params

This commit is contained in:
Agus Zubiaga 2024-05-09 21:56:41 -03:00
parent 96e2d32fa6
commit 9d26adb228
No known key found for this signature in database
6 changed files with 112 additions and 42 deletions

View file

@ -3,7 +3,7 @@ use crate::procedure::{QualifiedReference, References};
use crate::scope::{PendingAbilitiesInScope, Scope}; use crate::scope::{PendingAbilitiesInScope, Scope};
use roc_collections::{ImMap, MutSet, SendMap, VecMap, VecSet}; use roc_collections::{ImMap, MutSet, SendMap, VecMap, VecSet};
use roc_module::ident::{Ident, Lowercase, TagName}; use roc_module::ident::{Ident, Lowercase, TagName};
use roc_module::symbol::Symbol; use roc_module::symbol::{LookedupSymbol, Symbol};
use roc_parse::ast::{AssignedField, ExtractSpaces, Pattern, Tag, TypeAnnotation, TypeHeader}; use roc_parse::ast::{AssignedField, ExtractSpaces, Pattern, Tag, TypeAnnotation, TypeHeader};
use roc_problem::can::ShadowKind; use roc_problem::can::ShadowKind;
use roc_region::all::{Loc, Region}; use roc_region::all::{Loc, Region};
@ -398,7 +398,7 @@ pub(crate) fn make_apply_symbol(
} }
} else { } else {
match env.qualified_lookup(scope, module_name, ident, region) { match env.qualified_lookup(scope, module_name, ident, region) {
Ok(symbol) => { Ok(LookedupSymbol { symbol, params: _ }) => {
references.insert_type_lookup(symbol, QualifiedReference::Qualified); references.insert_type_lookup(symbol, QualifiedReference::Qualified);
Ok(symbol) Ok(symbol)
} }

View file

@ -32,6 +32,7 @@ use roc_module::ident::Lowercase;
use roc_module::ident::ModuleName; use roc_module::ident::ModuleName;
use roc_module::ident::QualifiedModuleName; use roc_module::ident::QualifiedModuleName;
use roc_module::symbol::IdentId; use roc_module::symbol::IdentId;
use roc_module::symbol::LookedupSymbol;
use roc_module::symbol::ModuleId; use roc_module::symbol::ModuleId;
use roc_module::symbol::Symbol; use roc_module::symbol::Symbol;
use roc_parse::ast; use roc_parse::ast;
@ -512,19 +513,21 @@ fn canonicalize_claimed_ability_impl<'a>(
let label_str = label.value; let label_str = label.value;
let region = label.region; let region = label.region;
let member_symbol = let LookedupSymbol {
match env.qualified_lookup_with_module_id(scope, ability_home, label_str, region) { symbol: member_symbol,
Ok(symbol) => symbol, params: _,
Err(_) => { } = match env.qualified_lookup_with_module_id(scope, ability_home, label_str, region) {
env.problem(Problem::NotAnAbilityMember { Ok(symbol) => symbol,
ability, Err(_) => {
name: label_str.to_owned(), env.problem(Problem::NotAnAbilityMember {
region, ability,
}); name: label_str.to_owned(),
region,
});
return Err(()); return Err(());
} }
}; };
// There are two options for how the implementation symbol is defined. // There are two options for how the implementation symbol is defined.
// //
@ -604,7 +607,10 @@ fn canonicalize_claimed_ability_impl<'a>(
}; };
let impl_region = value.region; let impl_region = value.region;
let member_symbol = match env.qualified_lookup_with_module_id( let LookedupSymbol {
symbol: member_symbol,
params: _,
} = match env.qualified_lookup_with_module_id(
scope, scope,
ability_home, ability_home,
label.value, label.value,

View file

@ -5,7 +5,10 @@ use crate::scope::Scope;
use bumpalo::Bump; use bumpalo::Bump;
use roc_collections::{MutMap, VecSet}; use roc_collections::{MutMap, VecSet};
use roc_module::ident::{Ident, ModuleName}; use roc_module::ident::{Ident, ModuleName};
use roc_module::symbol::{IdentIdsByModule, ModuleId, PQModuleName, PackageModuleIds, Symbol}; use roc_module::symbol::{
IdentIdsByModule, LookedupModule, LookedupSymbol, ModuleId, PQModuleName, PackageModuleIds,
Symbol,
};
use roc_problem::can::{Problem, RuntimeError}; use roc_problem::can::{Problem, RuntimeError};
use roc_region::all::{Loc, Region}; use roc_region::all::{Loc, Region};
@ -74,7 +77,7 @@ impl<'a> Env<'a> {
module_name_str: &str, module_name_str: &str,
ident: &str, ident: &str,
region: Region, region: Region,
) -> Result<Symbol, RuntimeError> { ) -> Result<LookedupSymbol, RuntimeError> {
debug_assert!( debug_assert!(
!module_name_str.is_empty(), !module_name_str.is_empty(),
"Called env.qualified_lookup with an unqualified ident: {ident:?}" "Called env.qualified_lookup with an unqualified ident: {ident:?}"
@ -82,8 +85,10 @@ impl<'a> Env<'a> {
let module_name = ModuleName::from(module_name_str); let module_name = ModuleName::from(module_name_str);
match scope.modules.get_id(&module_name) { match scope.modules.lookup(&module_name) {
Some(module_id) => self.qualified_lookup_help(scope, module_id, ident, region), Some(lookedup_module) => {
self.qualified_lookup_help(scope, lookedup_module, ident, region)
}
None => Err(RuntimeError::ModuleNotImported { None => Err(RuntimeError::ModuleNotImported {
module_name: module_name.clone(), module_name: module_name.clone(),
imported_modules: scope imported_modules: scope
@ -106,11 +111,11 @@ impl<'a> Env<'a> {
module_id: ModuleId, module_id: ModuleId,
ident: &str, ident: &str,
region: Region, region: Region,
) -> Result<Symbol, RuntimeError> { ) -> Result<LookedupSymbol, RuntimeError> {
if !scope.modules.has_id(module_id) { if let Some(module) = scope.modules.lookup_by_id(&module_id) {
Err(self.module_exists_but_not_imported(scope, module_id, region)) self.qualified_lookup_help(scope, module, ident, region)
} else { } else {
self.qualified_lookup_help(scope, module_id, ident, region) Err(self.module_exists_but_not_imported(scope, module_id, region))
} }
} }
@ -118,18 +123,18 @@ impl<'a> Env<'a> {
fn qualified_lookup_help( fn qualified_lookup_help(
&mut self, &mut self,
scope: &Scope, scope: &Scope,
module_id: ModuleId, module: LookedupModule,
ident: &str, ident: &str,
region: Region, region: Region,
) -> Result<Symbol, RuntimeError> { ) -> Result<LookedupSymbol, RuntimeError> {
let is_type_name = ident.starts_with(|c: char| c.is_uppercase()); let is_type_name = ident.starts_with(|c: char| c.is_uppercase());
// You can do qualified lookups on your own module, e.g. // You can do qualified lookups on your own module, e.g.
// if I'm in the Foo module, I can do a `Foo.bar` lookup. // if I'm in the Foo module, I can do a `Foo.bar` lookup.
if module_id == self.home { if module.id == self.home {
match scope.locals.ident_ids.get_id(ident) { match scope.locals.ident_ids.get_id(ident) {
Some(ident_id) => { Some(ident_id) => {
let symbol = Symbol::new(module_id, ident_id); let symbol = Symbol::new(module.id, ident_id);
if is_type_name { if is_type_name {
self.qualified_type_lookups.insert(symbol); self.qualified_type_lookups.insert(symbol);
@ -137,7 +142,7 @@ impl<'a> Env<'a> {
self.qualified_value_lookups.insert(symbol); self.qualified_value_lookups.insert(symbol);
} }
Ok(symbol) Ok(LookedupSymbol::no_params(symbol))
} }
None => { None => {
let error = RuntimeError::LookupNotInScope { let error = RuntimeError::LookupNotInScope {
@ -157,10 +162,10 @@ impl<'a> Env<'a> {
} }
} }
} else { } else {
match self.dep_idents.get(&module_id) { match self.dep_idents.get(&module.id) {
Some(exposed_ids) => match exposed_ids.get_id(ident) { Some(exposed_ids) => match exposed_ids.get_id(ident) {
Some(ident_id) => { Some(ident_id) => {
let symbol = Symbol::new(module_id, ident_id); let symbol = Symbol::new(module.id, ident_id);
if is_type_name { if is_type_name {
self.qualified_type_lookups.insert(symbol); self.qualified_type_lookups.insert(symbol);
@ -168,12 +173,12 @@ impl<'a> Env<'a> {
self.qualified_value_lookups.insert(symbol); self.qualified_value_lookups.insert(symbol);
} }
Ok(symbol) Ok(module.into_symbol(symbol))
} }
None => Err(RuntimeError::ValueNotExposed { None => Err(RuntimeError::ValueNotExposed {
module_name: self module_name: self
.qualified_module_ids .qualified_module_ids
.get_name(module_id) .get_name(module.id)
.expect("Module ID known, but not in the module IDs somehow") .expect("Module ID known, but not in the module IDs somehow")
.as_inner() .as_inner()
.clone(), .clone(),
@ -182,7 +187,7 @@ impl<'a> Env<'a> {
exposed_values: exposed_ids.exposed_values(), exposed_values: exposed_ids.exposed_values(),
}), }),
}, },
_ => Err(self.module_exists_but_not_imported(scope, module_id, region)), _ => Err(self.module_exists_but_not_imported(scope, module.id, region)),
} }
} }
} }

View file

@ -1884,19 +1884,23 @@ fn canonicalize_var_lookup(
// Since module_name was nonempty, this is a qualified var. // Since module_name was nonempty, this is a qualified var.
// Look it up in the env! // Look it up in the env!
match env.qualified_lookup(scope, module_name, ident, region) { match env.qualified_lookup(scope, module_name, ident, region) {
Ok(symbol) => { Ok(lookedup_symbol) => {
output output
.references .references
.insert_value_lookup(symbol, QualifiedReference::Qualified); .insert_value_lookup(lookedup_symbol.symbol, QualifiedReference::Qualified);
if scope.abilities_store.is_ability_member_name(symbol) { if scope
.abilities_store
.is_ability_member_name(lookedup_symbol.symbol)
{
// todo(agus): params for abilities?
AbilityMember( AbilityMember(
symbol, lookedup_symbol.symbol,
Some(scope.abilities_store.fresh_specialization_id()), Some(scope.abilities_store.fresh_specialization_id()),
var_store.fresh(), var_store.fresh(),
) )
} else { } else {
Var(symbol, var_store.fresh()) Var(lookedup_symbol, var_store.fresh())
} }
} }
Err(problem) => { Err(problem) => {

View file

@ -84,6 +84,13 @@ impl<K: PartialEq, V> VecMap<K, V> {
} }
} }
pub fn get_with_index(&self, key: &K) -> Option<(usize, &V)> {
self.keys
.iter()
.position(|x| x == key)
.map(|index| (index, &self.values[index]))
}
pub fn get_mut(&mut self, key: &K) -> Option<&mut V> { pub fn get_mut(&mut self, key: &K) -> Option<&mut V> {
match self.keys.iter().position(|x| x == key) { match self.keys.iter().position(|x| x == key) {
None => None, None => None,
@ -152,6 +159,12 @@ impl<K: PartialEq, V> VecMap<K, V> {
} }
} }
impl<K, V: PartialEq> VecMap<K, V> {
pub fn get_index_by_value(&self, value: &V) -> Option<usize> {
self.values.iter().position(|x| x == value)
}
}
impl<K: PartialEq, V> Extend<(K, V)> for VecMap<K, V> { impl<K: PartialEq, V> Extend<(K, V)> for VecMap<K, V> {
#[inline(always)] #[inline(always)]
fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) { fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {

View file

@ -622,6 +622,22 @@ impl ModuleIds {
} }
} }
#[derive(Debug, Clone)]
pub struct LookedupSymbol {
pub symbol: Symbol,
pub params: Option<Symbol>,
}
impl LookedupSymbol {
pub fn new(symbol: Symbol, params: Option<Symbol>) -> Self {
Self { symbol, params }
}
pub fn no_params(symbol: Symbol) -> Self {
Self::new(symbol, None)
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ScopeModules { pub struct ScopeModules {
modules: VecMap<ModuleName, ModuleId>, modules: VecMap<ModuleName, ModuleId>,
@ -629,6 +645,22 @@ pub struct ScopeModules {
params: Vec<Option<Symbol>>, params: Vec<Option<Symbol>>,
} }
pub struct LookedupModule {
pub id: ModuleId,
pub params: Option<Symbol>,
}
impl LookedupModule {
pub fn into_symbol(&self, symbol: Symbol) -> LookedupSymbol {
debug_assert_eq!(symbol.module_id(), self.id);
LookedupSymbol {
symbol,
params: self.params,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ScopeModuleSource { pub enum ScopeModuleSource {
Builtin, Builtin,
@ -637,12 +669,22 @@ pub enum ScopeModuleSource {
} }
impl ScopeModules { impl ScopeModules {
pub fn get_id(&self, module_name: &ModuleName) -> Option<ModuleId> { pub fn lookup(&self, module_name: &ModuleName) -> Option<LookedupModule> {
self.modules.get(module_name).copied() self.modules
.get_with_index(module_name)
.map(|(index, module_id)| LookedupModule {
id: *module_id,
params: self.params.get(index).copied().unwrap(),
})
} }
pub fn has_id(&self, module_id: ModuleId) -> bool { pub fn lookup_by_id(&self, module_id: &ModuleId) -> Option<LookedupModule> {
self.sources.contains_key(&module_id) self.modules
.get_index_by_value(module_id)
.map(|index| LookedupModule {
id: *module_id,
params: self.params.get(index).copied().unwrap(),
})
} }
pub fn available_names(&self) -> impl Iterator<Item = &ModuleName> { pub fn available_names(&self) -> impl Iterator<Item = &ModuleName> {