Skip to content

Commit

Permalink
Merge d801db2 into ad69c54
Browse files Browse the repository at this point in the history
  • Loading branch information
jfecher authored Aug 26, 2024
2 parents ad69c54 + d801db2 commit 7d8a939
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 73 deletions.
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/elaborator/statements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ impl<'context> Elaborator<'context> {
// If we get here the type has no field named 'access.rhs'.
// Now we specialize the error message based on whether we know the object type in question yet.
if let Type::TypeVariable(..) = &lhs_type {
self.push_err(TypeCheckError::TypeAnnotationsNeeded { span });
self.push_err(TypeCheckError::TypeAnnotationsNeededForFieldAccess { span });
} else if lhs_type != Type::Error {
self.push_err(TypeCheckError::AccessUnknownMember {
lhs_type,
Expand Down
42 changes: 30 additions & 12 deletions compiler/noirc_frontend/src/elaborator/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ use crate::{
SecondaryAttribute, Signedness, UnaryOp, UnresolvedType, UnresolvedTypeData,
},
node_interner::{
DefinitionKind, DependencyId, ExprId, FuncId, GlobalId, TraitId, TraitImplKind,
TraitMethodId,
DefinitionKind, DependencyId, ExprId, FuncId, GlobalId, ImplSearchErrorKind, TraitId,
TraitImplKind, TraitMethodId,
},
Generics, Kind, ResolvedGeneric, Type, TypeBinding, TypeBindings, TypeVariable,
TypeVariableKind,
Expand Down Expand Up @@ -122,7 +122,7 @@ impl<'context> Elaborator<'context> {
Unit => Type::Unit,
Unspecified => {
let span = typ.span;
self.push_err(TypeCheckError::TypeAnnotationsNeeded { span });
self.push_err(TypeCheckError::UnspecifiedType { span });
Type::Error
}
Error => Type::Error,
Expand Down Expand Up @@ -482,7 +482,7 @@ impl<'context> Elaborator<'context> {
match self.interner.lookup_trait_implementation(&object_type, trait_id, &ordered, &named) {
Ok(impl_kind) => self.get_associated_type_from_trait_impl(path, impl_kind),
Err(constraints) => {
self.push_trait_constraint_error(constraints, span);
self.push_trait_constraint_error(&object_type, constraints, span);
Type::Error
}
}
Expand Down Expand Up @@ -1332,7 +1332,7 @@ impl<'context> Elaborator<'context> {

// The type variable must be unbound at this point since follow_bindings was called
Type::TypeVariable(_, TypeVariableKind::Normal) => {
self.push_err(TypeCheckError::TypeAnnotationsNeeded { span });
self.push_err(TypeCheckError::TypeAnnotationsNeededForMethodCall { span });
None
}

Expand Down Expand Up @@ -1596,16 +1596,34 @@ impl<'context> Elaborator<'context> {
Ok(impl_kind) => {
self.interner.select_impl_for_expression(function_ident_id, impl_kind);
}
Err(constraints) => self.push_trait_constraint_error(constraints, span),
Err(error) => self.push_trait_constraint_error(object_type, error, span),
}
}

fn push_trait_constraint_error(&mut self, constraints: Vec<TraitConstraint>, span: Span) {
if constraints.is_empty() {
self.push_err(TypeCheckError::TypeAnnotationsNeeded { span });
} else if let Some(error) = NoMatchingImplFoundError::new(self.interner, constraints, span)
{
self.push_err(TypeCheckError::NoMatchingImplFound(error));
fn push_trait_constraint_error(
&mut self,
object_type: &Type,
error: ImplSearchErrorKind,
span: Span,
) {
match error {
ImplSearchErrorKind::TypeAnnotationsNeededOnObjectType => {
self.push_err(TypeCheckError::TypeAnnotationsNeededForMethodCall { span });
}
ImplSearchErrorKind::Nested(constraints) => {
if let Some(error) = NoMatchingImplFoundError::new(self.interner, constraints, span)
{
self.push_err(TypeCheckError::NoMatchingImplFound(error));
}
}
ImplSearchErrorKind::MultipleMatching(candidates) => {
let object_type = object_type.clone();
self.push_err(TypeCheckError::MultipleMatchingImpls {
object_type,
span,
candidates,
});
}
}
}

Expand Down
34 changes: 32 additions & 2 deletions compiler/noirc_frontend/src/hir/comptime/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,11 +188,19 @@ pub enum InterpreterError {
FunctionAlreadyResolved {
location: Location,
},
MultipleMatchingImpls {
object_type: Type,
candidates: Vec<String>,
location: Location,
},

Unimplemented {
item: String,
location: Location,
},
TypeAnnotationsNeededForMethodCall {
location: Location,
},

// These cases are not errors, they are just used to prevent us from running more code
// until the loop can be resumed properly. These cases will never be displayed to users.
Expand Down Expand Up @@ -257,8 +265,10 @@ impl InterpreterError {
| InterpreterError::ContinueNotInLoop { location, .. }
| InterpreterError::TraitDefinitionMustBeAPath { location }
| InterpreterError::FailedToResolveTraitDefinition { location }
| InterpreterError::FailedToResolveTraitBound { location, .. } => *location,
InterpreterError::FunctionAlreadyResolved { location, .. } => *location,
| InterpreterError::FailedToResolveTraitBound { location, .. }
| InterpreterError::FunctionAlreadyResolved { location, .. }
| InterpreterError::MultipleMatchingImpls { location, .. }
| InterpreterError::TypeAnnotationsNeededForMethodCall { location } => *location,

InterpreterError::FailedToParseMacro { error, file, .. } => {
Location::new(error.span(), *file)
Expand Down Expand Up @@ -527,6 +537,26 @@ impl<'a> From<&'a InterpreterError> for CustomDiagnostic {
.to_string();
CustomDiagnostic::simple_error(msg, secondary, location.span)
}
InterpreterError::MultipleMatchingImpls { object_type, candidates, location } => {
let message = format!("Multiple trait impls match the object type `{object_type}`");
let secondary = "Ambiguous impl".to_string();
let mut error = CustomDiagnostic::simple_error(message, secondary, location.span);
for (i, candidate) in candidates.iter().enumerate() {
error.add_note(format!("Candidate {}: `{candidate}`", i + 1));
}
error
}
InterpreterError::TypeAnnotationsNeededForMethodCall { location } => {
let mut error = CustomDiagnostic::simple_error(
"Object type is unknown in method call".to_string(),
"Type must be known by this point to know which method to call".to_string(),
location.span,
);
let message =
"Try adding a type annotation for the object type before this method call";
error.add_note(message.to_string());
error
}
}
}
}
50 changes: 43 additions & 7 deletions compiler/noirc_frontend/src/hir/type_check/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,12 @@ pub enum TypeCheckError {
second_type: String,
second_index: usize,
},
#[error("Cannot infer type of expression, type annotations needed before this point")]
TypeAnnotationsNeeded { span: Span },
#[error("Object type is unknown in method call")]
TypeAnnotationsNeededForMethodCall { span: Span },
#[error("Object type is unknown in field access")]
TypeAnnotationsNeededForFieldAccess { span: Span },
#[error("Multiple trait impls may apply to this object type")]
MultipleMatchingImpls { object_type: Type, candidates: Vec<String>, span: Span },
#[error("use of deprecated function {name}")]
CallDeprecated { name: String, note: Option<String>, span: Span },
#[error("{0}")]
Expand Down Expand Up @@ -166,6 +170,10 @@ pub enum TypeCheckError {
NoSuchNamedTypeArg { name: Ident, item: String },
#[error("`{item}` is missing the associated type `{name}`")]
MissingNamedTypeArg { name: Rc<String>, item: String, span: Span },
#[error("Internal compiler error: type unspecified for value")]
UnspecifiedType { span: Span },
#[error("Binding `{typ}` here to the `_` inside would create a cyclic type")]
CyclicType { typ: Type, span: Span },
}

#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down Expand Up @@ -286,11 +294,33 @@ impl<'a> From<&'a TypeCheckError> for Diagnostic {
format!("return type is {typ}"),
*span,
),
TypeCheckError::TypeAnnotationsNeeded { span } => Diagnostic::simple_error(
"Expression type is ambiguous".to_string(),
"Type must be known at this point".to_string(),
*span,
),
TypeCheckError::TypeAnnotationsNeededForMethodCall { span } => {
let mut error = Diagnostic::simple_error(
"Object type is unknown in method call".to_string(),
"Type must be known by this point to know which method to call".to_string(),
*span,
);
error.add_note("Try adding a type annotation for the object type before this method call".to_string());
error
},
TypeCheckError::TypeAnnotationsNeededForFieldAccess { span } => {
let mut error = Diagnostic::simple_error(
"Object type is unknown in field access".to_string(),
"Type must be known by this point".to_string(),
*span,
);
error.add_note("Try adding a type annotation for the object type before this expression".to_string());
error
},
TypeCheckError::MultipleMatchingImpls { object_type, candidates, span } => {
let message = format!("Multiple trait impls match the object type `{object_type}`");
let secondary = "Ambiguous impl".to_string();
let mut error = Diagnostic::simple_error(message, secondary, *span);
for (i, candidate) in candidates.iter().enumerate() {
error.add_note(format!("Candidate {}: `{candidate}`", i + 1));
}
error
},
TypeCheckError::ResolverError(error) => error.into(),
TypeCheckError::TypeMismatchWithSource { expected, actual, span, source } => {
let message = match source {
Expand Down Expand Up @@ -388,6 +418,12 @@ impl<'a> From<&'a TypeCheckError> for Diagnostic {
TypeCheckError::UnsafeFn { span } => {
Diagnostic::simple_warning(error.to_string(), String::new(), *span)
}
TypeCheckError::UnspecifiedType { span } => {
Diagnostic::simple_error(error.to_string(), String::new(), *span)
}
TypeCheckError::CyclicType { typ: _, span } => {
Diagnostic::simple_error(error.to_string(), "Cyclic types have unlimited size and are prohibited in Noir".into(), *span)
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/hir_def/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,7 @@ impl TypeVariable {
};

if binding.occurs(id) {
Err(TypeCheckError::TypeAnnotationsNeeded { span })
Err(TypeCheckError::CyclicType { span, typ: binding })
} else {
*self.1.borrow_mut() = TypeBinding::Bound(binding);
Ok(())
Expand Down
28 changes: 16 additions & 12 deletions compiler/noirc_frontend/src/monomorphization/errors.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
use noirc_errors::{CustomDiagnostic, FileDiagnostic, Location};

use crate::hir::comptime::InterpreterError;
use crate::{hir::comptime::InterpreterError, Type};

#[derive(Debug)]
pub enum MonomorphizationError {
UnknownArrayLength { location: Location },
TypeAnnotationsNeeded { location: Location },
UnknownArrayLength { length: Type, location: Location },
NoDefaultType { location: Location },
InternalError { message: &'static str, location: Location },
InterpreterError(InterpreterError),
}

impl MonomorphizationError {
fn location(&self) -> Location {
match self {
MonomorphizationError::UnknownArrayLength { location }
MonomorphizationError::UnknownArrayLength { location, .. }
| MonomorphizationError::InternalError { location, .. }
| MonomorphizationError::TypeAnnotationsNeeded { location } => *location,
| MonomorphizationError::NoDefaultType { location, .. } => *location,
MonomorphizationError::InterpreterError(error) => error.get_location(),
}
}
Expand All @@ -32,16 +32,20 @@ impl From<MonomorphizationError> for FileDiagnostic {

impl MonomorphizationError {
fn into_diagnostic(self) -> CustomDiagnostic {
let message = match self {
MonomorphizationError::UnknownArrayLength { .. } => {
"Length of generic array could not be determined."
let message = match &self {
MonomorphizationError::UnknownArrayLength { length, .. } => {
format!("ICE: Could not determine array length `{length}`")
}
MonomorphizationError::TypeAnnotationsNeeded { .. } => "Type annotations needed",
MonomorphizationError::InterpreterError(error) => return (&error).into(),
MonomorphizationError::InternalError { message, .. } => message,
MonomorphizationError::NoDefaultType { location } => {
let message = "Type annotation needed".into();
let secondary = "Could not determine type of generic argument".into();
return CustomDiagnostic::simple_error(message, secondary, location.span);
}
MonomorphizationError::InterpreterError(error) => return error.into(),
MonomorphizationError::InternalError { message, .. } => message.to_string(),
};

let location = self.location();
CustomDiagnostic::simple_error(message.into(), String::new(), location.span)
CustomDiagnostic::simple_error(message, String::new(), location.span)
}
}
29 changes: 20 additions & 9 deletions compiler/noirc_frontend/src/monomorphization/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use crate::ast::{FunctionKind, IntegerBitSize, Signedness, UnaryOp, Visibility};
use crate::hir::comptime::InterpreterError;
use crate::hir::type_check::NoMatchingImplFoundError;
use crate::node_interner::ExprId;
use crate::node_interner::{ExprId, ImplSearchErrorKind};
use crate::{
debug::DebugInstrumenter,
hir_def::{
Expand Down Expand Up @@ -569,7 +569,7 @@ impl<'interner> Monomorphizer<'interner> {

let length = length.evaluate_to_u32().ok_or_else(|| {
let location = self.interner.expr_location(&array);
MonomorphizationError::UnknownArrayLength { location }
MonomorphizationError::UnknownArrayLength { location, length }
})?;

let contents = try_vecmap(0..length, |_| self.expr(repeated_element))?;
Expand Down Expand Up @@ -936,7 +936,10 @@ impl<'interner> Monomorphizer<'interner> {
let element = Box::new(Self::convert_type(element.as_ref(), location)?);
let length = match length.evaluate_to_u32() {
Some(length) => length,
None => return Err(MonomorphizationError::TypeAnnotationsNeeded { location }),
None => {
let length = length.as_ref().clone();
return Err(MonomorphizationError::UnknownArrayLength { location, length });
}
};
ast::Type::Array(length, element)
}
Expand Down Expand Up @@ -969,7 +972,7 @@ impl<'interner> Monomorphizer<'interner> {
// and within a larger generic type.
let default = match kind.default_type() {
Some(typ) => typ,
None => return Err(MonomorphizationError::TypeAnnotationsNeeded { location }),
None => return Err(MonomorphizationError::NoDefaultType { location }),
};

let monomorphized_default = Self::convert_type(&default, location)?;
Expand Down Expand Up @@ -1074,7 +1077,7 @@ impl<'interner> Monomorphizer<'interner> {
// and within a larger generic type.
let default = match kind.default_type() {
Some(typ) => typ,
None => return Err(MonomorphizationError::TypeAnnotationsNeeded { location }),
None => return Err(MonomorphizationError::NoDefaultType { location }),
};

Self::check_type(&default, location)
Expand Down Expand Up @@ -1946,6 +1949,7 @@ pub fn resolve_trait_method(
let impl_id = match trait_impl {
TraitImplKind::Normal(impl_id) => impl_id,
TraitImplKind::Assumed { object_type, trait_generics } => {
let location = interner.expr_location(&expr_id);
match interner.lookup_trait_implementation(
&object_type,
method.trait_id,
Expand All @@ -1954,21 +1958,28 @@ pub fn resolve_trait_method(
) {
Ok(TraitImplKind::Normal(impl_id)) => impl_id,
Ok(TraitImplKind::Assumed { .. }) => {
let location = interner.expr_location(&expr_id);
return Err(InterpreterError::NoImpl { location });
}
Err(constraints) => {
let location = interner.expr_location(&expr_id);
Err(ImplSearchErrorKind::TypeAnnotationsNeededOnObjectType) => {
return Err(InterpreterError::TypeAnnotationsNeededForMethodCall { location });
}
Err(ImplSearchErrorKind::Nested(constraints)) => {
if let Some(error) =
NoMatchingImplFoundError::new(interner, constraints, location.span)
{
let file = location.file;
return Err(InterpreterError::NoMatchingImplFound { error, file });
} else {
let location = interner.expr_location(&expr_id);
return Err(InterpreterError::NoImpl { location });
}
}
Err(ImplSearchErrorKind::MultipleMatching(candidates)) => {
return Err(InterpreterError::MultipleMatchingImpls {
object_type,
location,
candidates,
});
}
}
}
};
Expand Down
Loading

0 comments on commit 7d8a939

Please sign in to comment.