Skip to content

Commit cac3c0e

Browse files
committed
Added ability to import and access public trait implementations from other modules
1 parent 44ca2e1 commit cac3c0e

File tree

7 files changed

+119
-54
lines changed

7 files changed

+119
-54
lines changed

Diff for: src/asg/implementation.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use super::{FuncRef, GenericTraitRef};
2-
use crate::source_files::Source;
1+
use super::{FuncRef, GenericTraitRef, ImplRef};
2+
use crate::{ast::Privacy, source_files::Source};
33
use indexmap::IndexMap;
44
use std::collections::HashMap;
55

@@ -10,3 +10,10 @@ pub struct Impl {
1010
pub source: Source,
1111
pub body: HashMap<String, FuncRef>,
1212
}
13+
14+
#[derive(Clone, Debug)]
15+
pub struct ImplDecl {
16+
pub impl_ref: ImplRef,
17+
pub source: Source,
18+
pub privacy: Privacy,
19+
}

Diff for: src/resolve/ctx.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pub struct ResolveCtx {
1111
pub globals_in_modules: HashMap<FsNodeId, HashMap<String, asg::GlobalVarDecl>>,
1212
pub helper_exprs_in_modules: HashMap<FsNodeId, HashMap<String, asg::HelperExprDecl>>,
1313
pub trait_haystacks: HashMap<FsNodeId, HashMap<String, asg::TraitRef>>,
14-
pub impls_in_modules: HashMap<FsNodeId, HashMap<String, asg::ImplRef>>,
14+
pub impls_in_modules: HashMap<FsNodeId, HashMap<String, asg::ImplDecl>>,
1515
}
1616

1717
impl ResolveCtx {

Diff for: src/resolve/error.rs

+6
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,9 @@ pub enum ResolveErrorKind {
221221
DuplicateTypeName {
222222
name: String,
223223
},
224+
DuplicateImplementationName {
225+
name: String,
226+
},
224227
CannotCreateOutOfRangeFloat,
225228
TypeAliasesCannotContainPolymorphs,
226229
FailedToConformArgumentToDefaultValue,
@@ -563,6 +566,9 @@ impl Display for ResolveErrorKind {
563566
ResolveErrorKind::DuplicateTypeName { name } => {
564567
write!(f, "Duplicate type name '{}'", name)?;
565568
}
569+
ResolveErrorKind::DuplicateImplementationName { name } => {
570+
write!(f, "Duplicate implementation name '{}'", name)?;
571+
}
566572
ResolveErrorKind::CannotCreateOutOfRangeFloat => {
567573
write!(f, "Cannot create out-of-range floating-point number")?;
568574
}

Diff for: src/resolve/expr/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ pub struct ResolveExprCtx<'ast, 'root_ctx> {
6161
pub types_in_modules: &'root_ctx HashMap<FsNodeId, HashMap<String, asg::TypeDecl>>,
6262
pub globals_in_modules: &'root_ctx HashMap<FsNodeId, HashMap<String, asg::GlobalVarDecl>>,
6363
pub helper_exprs_in_modules: &'root_ctx HashMap<FsNodeId, HashMap<String, asg::HelperExprDecl>>,
64-
pub impls_in_modules: &'root_ctx HashMap<FsNodeId, HashMap<String, asg::ImplRef>>,
64+
pub impls_in_modules: &'root_ctx HashMap<FsNodeId, HashMap<String, asg::ImplDecl>>,
6565
pub module_fs_node_id: FsNodeId,
6666
pub physical_fs_node_id: FsNodeId,
6767
pub current_constraints: CurrentConstraints,

Diff for: src/resolve/expr/static_member.rs

+46-16
Original file line numberDiff line numberDiff line change
@@ -91,24 +91,54 @@ pub fn resolve_impl_mention(
9191
impl_args: &[TypeArg],
9292
source: Source,
9393
) -> Result<(ImplRef, PolyCatalog), ResolveError> {
94-
let Some(impl_name) = impl_name.as_plain_str() else {
95-
return Err(ResolveError::other("Invalid implementation name", source));
96-
};
94+
let impl_decl = impl_name.as_plain_str().and_then(|impl_name| {
95+
ctx.impls_in_modules
96+
.get(&ctx.module_fs_node_id)
97+
.and_then(|impls| impls.get(impl_name))
98+
});
99+
100+
let impl_decl = impl_decl.ok_or(()).or_else(|_| {
101+
let mut matches = (!impl_name.namespace.is_empty())
102+
.then(|| {
103+
ctx.settings
104+
.namespace_to_dependency
105+
.get(impl_name.namespace.as_ref())
106+
})
107+
.flatten()
108+
.into_iter()
109+
.flatten()
110+
.flat_map(|dependency| {
111+
ctx.settings
112+
.dependency_to_module
113+
.get(dependency)
114+
.and_then(|module_fs_node_id| ctx.impls_in_modules.get(module_fs_node_id))
115+
.and_then(|imp| imp.get(impl_name.basename.as_ref()))
116+
.filter(|imp| imp.privacy.is_public())
117+
.into_iter()
118+
});
119+
120+
let Some(imp) = matches.next() else {
121+
return Err(ResolveError::other(
122+
format!("Undefined trait implementation '{}'", impl_name),
123+
source,
124+
));
125+
};
97126

98-
let impl_ref = ctx
99-
.impls_in_modules
100-
.get(&ctx.module_fs_node_id)
101-
.and_then(|impls| impls.get(impl_name));
127+
if matches.next().is_some() {
128+
return Err(ResolveError::other(
129+
format!("Ambiguous trait implementation '{}'", impl_name),
130+
source,
131+
));
132+
}
102133

103-
let Some(imp) = impl_ref.and_then(|found| ctx.asg.impls.get(*found)) else {
104-
return Err(ResolveError::other(
105-
format!("Undefined trait implementation '{}'", impl_name),
106-
source,
107-
));
108-
};
134+
Ok(imp)
135+
})?;
109136

110-
// Guaranteed to be valid now
111-
let impl_ref = impl_ref.unwrap();
137+
let imp = ctx
138+
.asg
139+
.impls
140+
.get(impl_decl.impl_ref)
141+
.expect("public impl of impl decl to exist");
112142

113143
if imp.name_params.len() != impl_args.len() {
114144
return Err(ResolveError::other(
@@ -135,7 +165,7 @@ pub fn resolve_impl_mention(
135165
}
136166
}
137167

138-
Ok((*impl_ref, catalog))
168+
Ok((impl_decl.impl_ref, catalog))
139169
}
140170

141171
pub fn resolve_static_member_call_named(

Diff for: src/resolve/impl_head/mod.rs

+48-18
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@ use super::{
44
func_head::create_func_head, job::FuncJob,
55
};
66
use crate::{
7-
asg::{self, Asg, CurrentConstraints, Func, GenericTraitRef, TraitFunc, Type},
8-
ast::{self, AstFile},
7+
asg::{
8+
self, Asg, CurrentConstraints, Func, GenericTraitRef, ImplDecl, ImplRef, TraitFunc, Type,
9+
},
10+
ast::{self, AstFile, Privacy},
911
cli::BuildOptions,
1012
name::{Name, ResolvedName},
1113
resolve::{error::ResolveErrorKind, type_ctx::ResolveTypeCtx},
14+
source_files::Source,
1215
workspace::fs::FsNodeId,
1316
};
1417
use for_alls::ForAlls;
@@ -305,16 +308,16 @@ fn matches(
305308
pub fn create_impl_head<'a>(
306309
ctx: &mut ResolveCtx,
307310
asg: &mut Asg<'a>,
308-
module_file_id: FsNodeId,
309-
physical_file_id: FsNodeId,
311+
module_fs_node_id: FsNodeId,
312+
physical_fs_node_id: FsNodeId,
310313
imp: &ast::Impl,
311314
) -> Result<asg::ImplRef, ResolveError> {
312315
let pre_parameters_constraints = CurrentConstraints::new_empty();
313316

314317
let type_ctx = ResolveTypeCtx::new(
315318
&asg,
316-
module_file_id,
317-
physical_file_id,
319+
module_fs_node_id,
320+
physical_fs_node_id,
318321
&ctx.types_in_modules,
319322
&pre_parameters_constraints,
320323
);
@@ -399,18 +402,14 @@ pub fn create_impl_head<'a>(
399402
.as_ref()
400403
.map_or("<unnamed impl>", |name| name.as_str());
401404

402-
if ctx
403-
.impls_in_modules
404-
.entry(module_file_id)
405-
.or_default()
406-
.insert(name.to_string(), impl_ref)
407-
.is_some()
408-
{
409-
return Err(ResolveErrorKind::Other {
410-
message: format!("Duplicate implementation name '{}'", name),
411-
}
412-
.at(imp.source));
413-
};
405+
declare_impl(
406+
ctx,
407+
module_fs_node_id,
408+
name,
409+
imp.source,
410+
imp.privacy,
411+
impl_ref,
412+
)?;
414413

415414
Ok(impl_ref)
416415
}
@@ -428,3 +427,34 @@ fn into_trait(ty: &Type) -> Result<GenericTraitRef, ResolveError> {
428427
args: args.clone(),
429428
})
430429
}
430+
431+
fn declare_impl(
432+
ctx: &mut ResolveCtx,
433+
module_fs_node_id: FsNodeId,
434+
name: &str,
435+
source: Source,
436+
privacy: Privacy,
437+
impl_ref: ImplRef,
438+
) -> Result<(), ResolveError> {
439+
if ctx
440+
.impls_in_modules
441+
.entry(module_fs_node_id)
442+
.or_default()
443+
.insert(
444+
name.to_string(),
445+
ImplDecl {
446+
impl_ref,
447+
privacy,
448+
source,
449+
},
450+
)
451+
.is_some()
452+
{
453+
return Err(ResolveErrorKind::DuplicateImplementationName {
454+
name: name.to_string(),
455+
}
456+
.at(source));
457+
};
458+
459+
Ok(())
460+
}

Diff for: tests/success/cast_trait/main.adept

+8-16
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,18 @@ pragma => {
66
}
77

88
#[foreign]
9-
func printf(format ptr<char>, ...) int
9+
func printf(format ptr#char, ...) int
1010

1111
func main {
12-
castTest(1234)::(myCastIntToDouble, myCastIntToLongLong)
12+
castTest(1234)::(std/castI32ToDouble, std/castI32ToLongLong)
1313
}
1414

15-
#[using std/Cast<int, double>]
16-
#[using std/Cast<int, longlong>]
17-
func castTest(x int) {
15+
#[using std/Cast<i32, double>]
16+
#[using std/Cast<i32, longlong>]
17+
func castTest(x i32) {
18+
printf(c"With long form generics syntax:\n")
1819
printf(c"%d %f %lld\n", x, x.cast<double>(), x.cast<longlong>())
20+
printf(c"With shorthand generics syntax:\n")
21+
printf(c"%d %f %lld\n", x, x.cast#double(), x.cast#longlong())
1922
}
2023

21-
impl std/Cast<int, double> myCastIntToDouble {
22-
func cast(from int) double {
23-
return from.double()
24-
}
25-
}
26-
27-
impl std/Cast<int, longlong> myCastIntToLongLong {
28-
func cast(from int) longlong {
29-
return from.longlong()
30-
}
31-
}

0 commit comments

Comments
 (0)