Skip to content

Commit

Permalink
feat: allow unquoting TraitConstraint in trait impl position (#7395)
Browse files Browse the repository at this point in the history
  • Loading branch information
asterite authored Feb 18, 2025
1 parent 8652072 commit 40d2763
Show file tree
Hide file tree
Showing 20 changed files with 246 additions and 129 deletions.
6 changes: 2 additions & 4 deletions compiler/noirc_frontend/src/ast/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,7 @@ pub struct TypeImpl {
pub struct NoirTraitImpl {
pub impl_generics: UnresolvedGenerics,

pub trait_name: Path,

pub trait_generics: GenericTypeArgs,
pub r#trait: UnresolvedType,

pub object_type: UnresolvedType,

Expand Down Expand Up @@ -247,7 +245,7 @@ impl Display for NoirTraitImpl {
)?;
}

write!(f, " {}{} for {}", self.trait_name, self.trait_generics, self.object_type)?;
write!(f, " {} for {}", self.r#trait, self.object_type)?;
if !self.where_clause.is_empty() {
write!(
f,
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/ast/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ impl NoirTraitImpl {
}

pub fn accept_children(&self, visitor: &mut impl Visitor) {
self.trait_name.accept(visitor);
self.r#trait.accept(visitor);
self.object_type.accept(visitor);

for item in &self.items {
Expand Down
3 changes: 1 addition & 2 deletions compiler/noirc_frontend/src/elaborator/comptime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -397,8 +397,7 @@ impl<'context> Elaborator<'context> {
generated_items.trait_impls.push(UnresolvedTraitImpl {
file_id: self.file,
module_id: self.local_module,
trait_generics: trait_impl.trait_generics,
trait_path: trait_impl.trait_name,
r#trait: trait_impl.r#trait,
object_type: trait_impl.object_type,
methods,
generics: trait_impl.impl_generics,
Expand Down
101 changes: 81 additions & 20 deletions compiler/noirc_frontend/src/elaborator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ use crate::{
},
graph::CrateId,
hir::{
def_collector::dc_crate::{
filter_literal_globals, CollectedItems, CompilationError, ImplMap, UnresolvedEnum,
UnresolvedFunctions, UnresolvedGlobal, UnresolvedStruct, UnresolvedTraitImpl,
UnresolvedTypeAlias,
def_collector::{
dc_crate::{
filter_literal_globals, CollectedItems, CompilationError, ImplMap, UnresolvedEnum,
UnresolvedFunctions, UnresolvedGlobal, UnresolvedStruct, UnresolvedTraitImpl,
UnresolvedTypeAlias,
},
errors::DefCollectorErrorKind,
},
def_collector::errors::DefCollectorErrorKind,
def_map::{DefMaps, ModuleData},
def_map::{LocalModuleId, ModuleId, MAIN_FUNCTION},
def_map::{DefMaps, LocalModuleId, ModuleData, ModuleId, MAIN_FUNCTION},
resolution::errors::ResolverError,
scope::ScopeForest as GenericScopeForest,
type_check::{generics::TraitGenerics, TypeCheckError},
Expand Down Expand Up @@ -1458,9 +1459,26 @@ impl<'context> Elaborator<'context> {
}

let trait_generics = trait_impl.resolved_trait_generics.clone();
let ident = match &trait_impl.r#trait.typ {
UnresolvedTypeData::Named(trait_path, _, _) => trait_path.last_ident(),
UnresolvedTypeData::Resolved(quoted_type_id) => {
let typ = self.interner.get_quoted_type(*quoted_type_id);
let name = if let Type::TraitAsType(_, name, _) = typ {
name.to_string()
} else {
typ.to_string()
};
Ident::new(name, trait_impl.r#trait.span)
}
_ => {
// We don't error in this case because an error will be produced later on when
// solving the trait impl trait type
Ident::new(trait_impl.r#trait.to_string(), trait_impl.r#trait.span)
}
};

let resolved_trait_impl = Shared::new(TraitImpl {
ident: trait_impl.trait_path.last_ident(),
ident,
typ: self_type.clone(),
trait_id,
trait_generics,
Expand Down Expand Up @@ -1983,7 +2001,49 @@ impl<'context> Elaborator<'context> {
self.file = trait_impl.file_id;
self.local_module = trait_impl.module_id;

let trait_id = self.resolve_trait_by_path(trait_impl.trait_path.clone());
let (trait_id, mut trait_generics, path_span) = match &trait_impl.r#trait.typ {
UnresolvedTypeData::Named(trait_path, trait_generics, _) => {
let trait_id = self.resolve_trait_by_path(trait_path.clone());
(trait_id, trait_generics.clone(), trait_path.span)
}
UnresolvedTypeData::Resolved(quoted_type_id) => {
let typ = self.interner.get_quoted_type(*quoted_type_id);
let span = trait_impl.r#trait.span;
let Type::TraitAsType(trait_id, _, trait_generics) = typ else {
let found = typ.to_string();
self.push_err(ResolverError::ExpectedTrait { span, found });
continue;
};

// In order to take associated types into account we turn these resolved generics
// into unresolved ones, but ones that point to solved types.
let trait_id = *trait_id;
let trait_generics = trait_generics.clone();
let trait_generics = GenericTypeArgs {
ordered_args: vecmap(&trait_generics.ordered, |typ| {
let quoted_type_id = self.interner.push_quoted_type(typ.clone());
let typ = UnresolvedTypeData::Resolved(quoted_type_id);
UnresolvedType { typ, span }
}),
named_args: vecmap(&trait_generics.named, |named_type| {
let quoted_type_id =
self.interner.push_quoted_type(named_type.typ.clone());
let typ = UnresolvedTypeData::Resolved(quoted_type_id);
(named_type.name.clone(), UnresolvedType { typ, span })
}),
kinds: Vec::new(),
};

(Some(trait_id), trait_generics, span)
}
_ => {
let span = trait_impl.r#trait.span;
let found = trait_impl.r#trait.typ.to_string();
self.push_err(ResolverError::ExpectedTrait { span, found });
continue;
}
};

trait_impl.trait_id = trait_id;
let unresolved_type = trait_impl.object_type.clone();

Expand All @@ -2006,14 +2066,12 @@ impl<'context> Elaborator<'context> {
method.def.where_clause.append(&mut trait_impl.where_clause.clone());
}

// Add each associated type to the list of named type arguments
let mut trait_generics = trait_impl.trait_generics.clone();
trait_generics.named_args.extend(self.take_unresolved_associated_types(trait_impl));

let impl_id = self.interner.next_trait_impl_id();
self.current_trait_impl = Some(impl_id);

let path_span = trait_impl.trait_path.span;
// Add each associated type to the list of named type arguments
trait_generics.named_args.extend(self.take_unresolved_associated_types(trait_impl));

let (ordered_generics, named_generics) = trait_impl
.trait_id
.map(|trait_id| {
Expand All @@ -2038,12 +2096,15 @@ impl<'context> Elaborator<'context> {
self.generics.clear();

if let Some(trait_id) = trait_id {
let trait_name = trait_impl.trait_path.last_ident();
self.interner.add_trait_reference(
trait_id,
Location::new(trait_name.span(), trait_impl.file_id),
trait_name.is_self_type_name(),
);
let (span, is_self_type_name) = match &trait_impl.r#trait.typ {
UnresolvedTypeData::Named(trait_path, _, _) => {
let trait_name = trait_path.last_ident();
(trait_name.span(), trait_name.is_self_type_name())
}
_ => (trait_impl.r#trait.span, false),
};
let location = Location::new(span, trait_impl.file_id);
self.interner.add_trait_reference(trait_id, location, is_self_type_name);
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions compiler/noirc_frontend/src/hir/comptime/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,11 @@ impl Value {
Value::UnresolvedType(typ) => {
Token::InternedUnresolvedTypeData(interner.push_unresolved_type_data(typ))
}
Value::TraitConstraint(trait_id, generics) => {
let name = Rc::new(interner.get_trait(trait_id).name.0.contents.clone());
let typ = Type::TraitAsType(trait_id, name, generics);
Token::QuotedType(interner.push_quoted_type(typ))
}
Value::TypedExpr(TypedExpr::ExprId(expr_id)) => Token::UnquoteMarker(expr_id),
Value::U1(bool) => Token::Bool(bool),
Value::U8(value) => Token::Int((value as u128).into()),
Expand Down
7 changes: 3 additions & 4 deletions compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ use crate::node_interner::{
};

use crate::ast::{
ExpressionKind, GenericTypeArgs, Ident, ItemVisibility, LetStatement, Literal, NoirFunction,
NoirStruct, NoirTrait, NoirTypeAlias, Path, PathKind, PathSegment, UnresolvedGenerics,
ExpressionKind, Ident, ItemVisibility, LetStatement, Literal, NoirFunction, NoirStruct,
NoirTrait, NoirTypeAlias, Path, PathKind, PathSegment, UnresolvedGenerics,
UnresolvedTraitConstraint, UnresolvedType, UnsupportedNumericGenericType,
};

Expand Down Expand Up @@ -83,8 +83,7 @@ pub struct UnresolvedTrait {
pub struct UnresolvedTraitImpl {
pub file_id: FileId,
pub module_id: LocalModuleId,
pub trait_generics: GenericTypeArgs,
pub trait_path: Path,
pub r#trait: UnresolvedType,
pub object_type: UnresolvedType,
pub methods: UnresolvedFunctions,
pub generics: UnresolvedGenerics,
Expand Down
5 changes: 1 addition & 4 deletions compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,6 @@ impl<'a> ModCollector<'a> {
let mut errors = Vec::new();

for mut trait_impl in impls {
let trait_name = trait_impl.trait_name.clone();

let (mut unresolved_functions, associated_types, associated_constants) =
collect_trait_impl_items(
&mut context.def_interner,
Expand Down Expand Up @@ -233,12 +231,11 @@ impl<'a> ModCollector<'a> {
let unresolved_trait_impl = UnresolvedTraitImpl {
file_id: self.file_id,
module_id: self.module_id,
trait_path: trait_name,
r#trait: trait_impl.r#trait,
methods: unresolved_functions,
object_type: trait_impl.object_type,
generics: trait_impl.impl_generics,
where_clause: trait_impl.where_clause,
trait_generics: trait_impl.trait_generics,
associated_constants,
associated_types,

Expand Down
9 changes: 9 additions & 0 deletions compiler/noirc_frontend/src/hir/resolution/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ pub enum ResolverError {
},
#[error("`loop` statements are not yet implemented")]
LoopNotYetSupported { span: Span },
#[error("Expected a trait but found {found}")]
ExpectedTrait { found: String, span: Span },
}

impl ResolverError {
Expand Down Expand Up @@ -687,6 +689,13 @@ impl<'a> From<&'a ResolverError> for Diagnostic {
*span)

}
ResolverError::ExpectedTrait { found, span } => {
Diagnostic::simple_error(
format!("Expected a trait, found {found}"),
String::new(),
*span)

}
}
}
}
2 changes: 0 additions & 2 deletions compiler/noirc_frontend/src/parser/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ pub enum ParserErrorReason {
ExpectedMutAfterAmpersand { found: Token },
#[error("Invalid left-hand side of assignment")]
InvalidLeftHandSideOfAssignment,
#[error("Expected trait, found {found}")]
ExpectedTrait { found: String },
#[error("Visibility `{visibility}` is not followed by an item")]
VisibilityNotFollowedByAnItem { visibility: ItemVisibility },
#[error("`unconstrained` is not followed by an item")]
Expand Down
Loading

0 comments on commit 40d2763

Please sign in to comment.