Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Remove the remainder of legacy code #5525

Merged
merged 17 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 14 additions & 28 deletions aztec_macros/src/utils/hir_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ use acvm::acir::AcirField;
use iter_extended::vecmap;
use noirc_errors::Location;
use noirc_frontend::ast;
use noirc_frontend::elaborator::Elaborator;
use noirc_frontend::hir::def_collector::dc_crate::{
CollectedItems, UnresolvedFunctions, UnresolvedGlobal,
};
use noirc_frontend::macros_api::{HirExpression, HirLiteral};
use noirc_frontend::node_interner::{NodeInterner, TraitImplKind};
use noirc_frontend::{
graph::CrateId,
hir::{
def_map::{LocalModuleId, ModuleId},
resolution::{path_resolver::StandardPathResolver, resolver::Resolver},
type_check::type_check_func,
},
hir::def_map::{LocalModuleId, ModuleId},
macros_api::{FileId, HirContext, MacroError, ModuleDefId, StructId},
node_interner::{FuncId, TraitId},
Shared, StructType, Type,
Expand Down Expand Up @@ -190,24 +190,17 @@ pub fn inject_fn(
span: None,
})?;

let def_maps = &mut context.def_maps;

let path_resolver =
StandardPathResolver::new(ModuleId { local_id: module_id, krate: *crate_id });

let resolver = Resolver::new(&mut context.def_interner, &path_resolver, def_maps, file_id);

let (hir_func, meta, _) = resolver.resolve_function(func, func_id);
let mut items = CollectedItems::default();
let functions = vec![(module_id, func_id, func)];
let trait_id = None;
items.functions.push(UnresolvedFunctions { file_id, functions, trait_id, self_type: None });

context.def_interner.push_fn_meta(meta, func_id);
context.def_interner.update_fn(func_id, hir_func);

let errors = type_check_func(&mut context.def_interner, func_id);
let errors = Elaborator::elaborate(context, *crate_id, items, None);

if !errors.is_empty() {
return Err(MacroError {
primary_message: "Failed to type check autogenerated function".to_owned(),
secondary_message: Some(errors.iter().map(|err| err.to_string()).collect::<String>()),
secondary_message: Some(errors.iter().map(|err| err.0.to_string()).collect::<String>()),
span: None,
});
}
Expand Down Expand Up @@ -243,17 +236,10 @@ pub fn inject_global(
)
});

let def_maps = &mut context.def_maps;

let path_resolver =
StandardPathResolver::new(ModuleId { local_id: module_id, krate: *crate_id });

let mut resolver = Resolver::new(&mut context.def_interner, &path_resolver, def_maps, file_id);

let hir_stmt = resolver.resolve_global_let(global, global_id);
let mut items = CollectedItems::default();
items.globals.push(UnresolvedGlobal { file_id, module_id, global_id, stmt_def: global });

let statement_id = context.def_interner.get_global(global_id).let_statement;
context.def_interner.replace_statement(statement_id, hir_stmt);
let _errors = Elaborator::elaborate(context, *crate_id, items, None);
}

pub fn fully_qualified_note_path(context: &HirContext, note_id: StructId) -> Option<String> {
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/ast/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use super::{
BlockExpression, Expression, ExpressionKind, IndexExpression, MemberAccessExpression,
MethodCallExpression, UnresolvedType,
};
use crate::hir::resolution::resolver::SELF_TYPE_NAME;
use crate::elaborator::types::SELF_TYPE_NAME;
use crate::lexer::token::SpannedToken;
use crate::macros_api::SecondaryAttribute;
use crate::parser::{ParserError, ParserErrorReason};
Expand Down
4 changes: 2 additions & 2 deletions compiler/noirc_frontend/src/elaborator/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{
},
hir::{
comptime::{self, InterpreterError},
resolution::{errors::ResolverError, resolver::LambdaContext},
resolution::errors::ResolverError,
type_check::TypeCheckError,
},
hir_def::{
Expand All @@ -32,7 +32,7 @@ use crate::{
QuotedType, Shared, StructType, Type,
};

use super::Elaborator;
use super::{Elaborator, LambdaContext};

impl<'context> Elaborator<'context> {
pub(super) fn elaborate_expression(&mut self, expr: Expression) -> (ExprId, Type) {
Expand Down
17 changes: 13 additions & 4 deletions compiler/noirc_frontend/src/elaborator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ use crate::{
dc_mod,
errors::DuplicateType,
},
resolution::{errors::ResolverError, path_resolver::PathResolver, resolver::LambdaContext},
resolution::{errors::ResolverError, path_resolver::PathResolver},
scope::ScopeForest as GenericScopeForest,
type_check::{check_trait_impl_method_matches_declaration, TypeCheckError},
type_check::TypeCheckError,
},
hir_def::{
expr::HirIdent,
expr::{HirCapturedVar, HirIdent},
function::{FunctionBody, Parameters},
traits::TraitConstraint,
types::{Generics, Kind, ResolvedGeneric},
Expand Down Expand Up @@ -67,14 +67,16 @@ mod patterns;
mod scope;
mod statements;
mod traits;
mod types;
pub mod types;
mod unquote;

use fm::FileId;
use iter_extended::vecmap;
use noirc_errors::{Location, Span};
use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};

use self::traits::check_trait_impl_method_matches_declaration;

/// ResolverMetas are tagged onto each definition to track how many times they are used
#[derive(Debug, PartialEq, Eq)]
pub struct ResolverMeta {
Expand All @@ -85,6 +87,13 @@ pub struct ResolverMeta {

type ScopeForest = GenericScopeForest<String, ResolverMeta>;

pub struct LambdaContext {
pub captures: Vec<HirCapturedVar>,
/// the index in the scope tree
/// (sometimes being filled by ScopeTree's find method)
pub scope_index: usize,
}

pub struct Elaborator<'context> {
scopes: ScopeForest,

Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/elaborator/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use noirc_errors::{Location, Spanned};
use crate::ast::ERROR_IDENT;
use crate::hir::def_map::{LocalModuleId, ModuleId};
use crate::hir::resolution::path_resolver::{PathResolver, StandardPathResolver};
use crate::hir::resolution::resolver::SELF_TYPE_NAME;
use crate::hir::scope::{Scope as GenericScope, ScopeTree as GenericScopeTree};
use crate::macros_api::Ident;
use crate::{
Expand All @@ -21,6 +20,7 @@ use crate::{
};
use crate::{Type, TypeAlias};

use super::types::SELF_TYPE_NAME;
use super::{Elaborator, ResolverMeta};

type Scope = GenericScope<String, ResolverMeta>;
Expand Down
172 changes: 167 additions & 5 deletions compiler/noirc_frontend/src/elaborator/traits.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
use std::{collections::BTreeMap, rc::Rc};

use iter_extended::vecmap;
use noirc_errors::Location;
use noirc_errors::{Location, Span};

use crate::{
ast::{
FunctionKind, TraitItem, UnresolvedGeneric, UnresolvedGenerics, UnresolvedTraitConstraint,
},
hir::def_collector::dc_crate::{CollectedItems, UnresolvedTrait},
hir_def::traits::{TraitConstant, TraitFunction, TraitType},
hir::{
def_collector::dc_crate::{CollectedItems, UnresolvedTrait},
type_check::TypeCheckError,
},
hir_def::{
function::Parameters,
traits::{TraitConstant, TraitFunction, TraitType},
},
macros_api::{
BlockExpression, FunctionDefinition, FunctionReturnType, Ident, ItemVisibility,
NoirFunction, Param, Pattern, UnresolvedType, Visibility,
NodeInterner, NoirFunction, Param, Pattern, UnresolvedType, Visibility,
},
node_interner::{FuncId, TraitId},
token::Attributes,
Kind, ResolvedGeneric, Type, TypeVariableKind,
Kind, ResolvedGeneric, Type, TypeBindings, TypeVariableKind,
};

use super::Elaborator;
Expand Down Expand Up @@ -204,3 +210,159 @@ impl<'context> Elaborator<'context> {
self.generics.truncate(old_generic_count);
}
}

/// Checks that the type of a function in a trait impl matches the type
/// of the corresponding function declaration in the trait itself.
///
/// To do this, given a trait such as:
/// `trait Foo<A> { fn foo<B>(...); }`
///
/// And an impl such as:
/// `impl<C> Foo<D> for Bar<E> { fn foo<F>(...); } `
///
/// We have to substitute:
/// - Self for Bar<E>
/// - A for D
/// - B for F
///
/// Before we can type check. Finally, we must also check that the unification
/// result does not introduce any new bindings. This can happen if the impl
/// function's type is more general than that of the trait function. E.g.
/// `fn baz<A, B>(a: A, b: B)` when the impl required `fn baz<A>(a: A, b: A)`.
///
/// This does not type check the body of the impl function.
pub(crate) fn check_trait_impl_method_matches_declaration(
interner: &mut NodeInterner,
function: FuncId,
) -> Vec<TypeCheckError> {
let meta = interner.function_meta(&function);
let method_name = interner.function_name(&function);
let mut errors = Vec::new();

let definition_type = meta.typ.as_monotype();

let impl_ =
meta.trait_impl.expect("Trait impl function should have a corresponding trait impl");

// If the trait implementation is not defined in the interner then there was a previous
// error in resolving the trait path and there is likely no trait for this impl.
let Some(impl_) = interner.try_get_trait_implementation(impl_) else {
return errors;
};

let impl_ = impl_.borrow();
let trait_info = interner.get_trait(impl_.trait_id);

let mut bindings = TypeBindings::new();
bindings.insert(
trait_info.self_type_typevar_id,
(trait_info.self_type_typevar.clone(), impl_.typ.clone()),
);

if trait_info.generics.len() != impl_.trait_generics.len() {
let expected = trait_info.generics.len();
let found = impl_.trait_generics.len();
let span = impl_.ident.span();
let item = trait_info.name.to_string();
errors.push(TypeCheckError::GenericCountMismatch { item, expected, found, span });
}

// Substitute each generic on the trait with the corresponding generic on the impl
for (generic, arg) in trait_info.generics.iter().zip(&impl_.trait_generics) {
bindings.insert(generic.type_var.id(), (generic.type_var.clone(), arg.clone()));
}

// If this is None, the trait does not have the corresponding function.
// This error should have been caught in name resolution already so we don't
// issue an error for it here.
if let Some(trait_fn_id) = trait_info.method_ids.get(method_name) {
let trait_fn_meta = interner.function_meta(trait_fn_id);

if trait_fn_meta.direct_generics.len() != meta.direct_generics.len() {
let expected = trait_fn_meta.direct_generics.len();
let found = meta.direct_generics.len();
let span = meta.name.location.span;
let item = method_name.to_string();
errors.push(TypeCheckError::GenericCountMismatch { item, expected, found, span });
}

// Substitute each generic on the trait function with the corresponding generic on the impl function
for (
ResolvedGeneric { type_var: trait_fn_generic, .. },
ResolvedGeneric { name, type_var: impl_fn_generic, .. },
) in trait_fn_meta.direct_generics.iter().zip(&meta.direct_generics)
{
let arg = Type::NamedGeneric(impl_fn_generic.clone(), name.clone(), Kind::Normal);
bindings.insert(trait_fn_generic.id(), (trait_fn_generic.clone(), arg));
}

let (declaration_type, _) = trait_fn_meta.typ.instantiate_with_bindings(bindings, interner);

check_function_type_matches_expected_type(
&declaration_type,
definition_type,
method_name,
&meta.parameters,
meta.name.location.span,
&trait_info.name.0.contents,
&mut errors,
);
}

errors
}

fn check_function_type_matches_expected_type(
expected: &Type,
actual: &Type,
method_name: &str,
actual_parameters: &Parameters,
span: Span,
trait_name: &str,
errors: &mut Vec<TypeCheckError>,
) {
let mut bindings = TypeBindings::new();
// Shouldn't need to unify envs, they should always be equal since they're both free functions
if let (Type::Function(params_a, ret_a, _env_a), Type::Function(params_b, ret_b, _env_b)) =
(expected, actual)
{
if params_a.len() == params_b.len() {
for (i, (a, b)) in params_a.iter().zip(params_b.iter()).enumerate() {
if a.try_unify(b, &mut bindings).is_err() {
errors.push(TypeCheckError::TraitMethodParameterTypeMismatch {
method_name: method_name.to_string(),
expected_typ: a.to_string(),
actual_typ: b.to_string(),
parameter_span: actual_parameters.0[i].0.span(),
parameter_index: i + 1,
});
}
}

if ret_b.try_unify(ret_a, &mut bindings).is_err() {
errors.push(TypeCheckError::TypeMismatch {
expected_typ: ret_a.to_string(),
expr_typ: ret_b.to_string(),
expr_span: span,
});
}
} else {
errors.push(TypeCheckError::MismatchTraitImplNumParameters {
actual_num_parameters: params_b.len(),
expected_num_parameters: params_a.len(),
trait_name: trait_name.to_string(),
method_name: method_name.to_string(),
span,
});
}
}

// If result bindings is not empty, a type variable was bound which means the two
// signatures were not a perfect match. Note that this relies on us already binding
// all the expected generics to each other prior to this check.
if !bindings.is_empty() {
let expected_typ = expected.to_string();
let expr_typ = actual.to_string();
errors.push(TypeCheckError::TypeMismatch { expected_typ, expr_typ, expr_span: span });
}
}
Loading
Loading