diff --git a/compiler/noirc_frontend/src/elaborator/enums.rs b/compiler/noirc_frontend/src/elaborator/enums.rs index 88ff2f01f11..d86155b9a24 100644 --- a/compiler/noirc_frontend/src/elaborator/enums.rs +++ b/compiler/noirc_frontend/src/elaborator/enums.rs @@ -553,7 +553,8 @@ impl Elaborator<'_> { variables_defined: &mut Vec, ) -> Pattern { let location = constructor.typ.location; - let typ = self.resolve_type(constructor.typ); + let wildcard_allowed = true; + let typ = self.resolve_type(constructor.typ, wildcard_allowed); let Some((struct_name, mut expected_field_types)) = self.struct_name_and_field_types(&typ, location) diff --git a/compiler/noirc_frontend/src/elaborator/expressions.rs b/compiler/noirc_frontend/src/elaborator/expressions.rs index 6f7672af806..274856c1813 100644 --- a/compiler/noirc_frontend/src/elaborator/expressions.rs +++ b/compiler/noirc_frontend/src/elaborator/expressions.rs @@ -339,7 +339,9 @@ impl Elaborator<'_> { }, ); - let length = self.convert_expression_type(length, &Kind::u32(), location); + let wildcard_allowed = true; + let length = + self.convert_expression_type(length, &Kind::u32(), location, wildcard_allowed); let (repeated_element, elem_type) = self.elaborate_expression(*repeated_element); let length_clone = length.clone(); @@ -616,7 +618,9 @@ impl Elaborator<'_> { let generics = generics.map(|generics| { vecmap(generics, |generic| { let location = generic.location; - let typ = self.use_type_with_kind(generic, &Kind::Any); + let wildcard_allowed = true; + let typ = + self.use_type_with_kind(generic, &Kind::Any, wildcard_allowed); Located::from(location, typ) }) }); @@ -1042,7 +1046,8 @@ impl Elaborator<'_> { location: Location, ) -> (HirExpression, Type) { let (lhs, lhs_type) = self.elaborate_expression(cast.lhs); - let r#type = self.resolve_type(cast.r#type); + let wildcard_allowed = false; + let r#type = self.resolve_type(cast.r#type, wildcard_allowed); let result = self.check_cast(&lhs, &lhs_type, &r#type, location); let expr = HirExpression::Cast(HirCastExpression { lhs, r#type }); (expr, result) @@ -1278,7 +1283,8 @@ impl Elaborator<'_> { self.interner.next_type_variable_with_kind(Kind::Any) } } else { - self.resolve_type(typ) + let wildcard_allowed = false; + self.resolve_type(typ, wildcard_allowed) }; arg_types.push(typ.clone()); @@ -1463,7 +1469,8 @@ impl Elaborator<'_> { }, }; - let typ = self.use_type(constraint.typ.clone()); + let wildcard_allowed = true; + let typ = self.use_type(constraint.typ.clone(), wildcard_allowed); let Some(trait_bound) = self.use_trait_bound(&constraint.trait_bound) else { // resolve_trait_bound only returns None if it has already issued an error, so don't // issue another here. diff --git a/compiler/noirc_frontend/src/elaborator/mod.rs b/compiler/noirc_frontend/src/elaborator/mod.rs index d0f13302af1..d1250daf064 100644 --- a/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/compiler/noirc_frontend/src/elaborator/mod.rs @@ -679,13 +679,15 @@ impl<'context> Elaborator<'context> { pub(super) fn resolve_generic_kind(&mut self, generic: &UnresolvedGeneric) -> Kind { if let UnresolvedGeneric::Numeric { ident, typ } = generic { let unresolved_typ = typ.clone(); + let wildcard_allowed = false; let typ = if unresolved_typ.is_type_expression() { self.resolve_type_with_kind( unresolved_typ.clone(), &Kind::numeric(Type::default_int_type()), + wildcard_allowed, ) } else { - self.resolve_type(unresolved_typ.clone()) + self.resolve_type(unresolved_typ.clone(), wildcard_allowed) }; if !matches!(typ, Type::FieldElement | Type::Integer(_, _)) { let unsupported_typ_err = @@ -859,7 +861,8 @@ impl<'context> Elaborator<'context> { &mut self, constraint: &UnresolvedTraitConstraint, ) -> Option { - let typ = self.resolve_type(constraint.typ.clone()); + let wildcard_allowed = true; + let typ = self.resolve_type(constraint.typ.clone(), wildcard_allowed); let trait_bound = self.resolve_trait_bound(&constraint.trait_bound)?; let location = constraint.trait_bound.trait_path.location; @@ -885,9 +888,15 @@ impl<'context> Elaborator<'context> { let the_trait = self.lookup_trait_or_error(trait_path)?; let trait_id = the_trait.id; let location = bound.trait_path.location; + let wildcard_allowed = true; - let (ordered, named) = - self.resolve_type_args_inner(bound.trait_generics.clone(), trait_id, location, mode); + let (ordered, named) = self.resolve_type_args_inner( + bound.trait_generics.clone(), + trait_id, + location, + mode, + wildcard_allowed, + ); let trait_generics = TraitGenerics { ordered, named }; Some(ResolvedTraitBound { trait_id, trait_generics, location }) @@ -966,6 +975,7 @@ impl<'context> Elaborator<'context> { let mut parameters = Vec::new(); let mut parameter_types = Vec::new(); let mut parameter_idents = Vec::new(); + let wildcard_allowed = false; for Param { visibility, pattern, typ, location: _ } in func.parameters().iter().cloned() { self.run_lint(|_| { @@ -978,7 +988,7 @@ impl<'context> Elaborator<'context> { self.desugar_impl_trait_arg(path, args, &mut generics, &mut trait_constraints) } // Function parameters have Kind::Normal - _ => self.resolve_type_with_kind(typ, &Kind::Normal), + _ => self.resolve_type_with_kind(typ, &Kind::Normal, wildcard_allowed), }; self.check_if_type_is_valid_for_program_input( @@ -1004,7 +1014,7 @@ impl<'context> Elaborator<'context> { parameter_types.push(typ); } - let return_type = Box::new(self.use_type(func.return_type())); + let return_type = Box::new(self.use_type(func.return_type(), wildcard_allowed)); let mut typ = Type::Function( parameter_types, @@ -1538,8 +1548,12 @@ impl<'context> Elaborator<'context> { // This can't be done in code, but it could happen with unquoted types. continue; }; - let resolved_type = - self.resolve_type_with_kind(unresolved_type, &associated_type.typ.kind()); + let wildcard_allowed = false; + let resolved_type = self.resolve_type_with_kind( + unresolved_type, + &associated_type.typ.kind(), + wildcard_allowed, + ); named_generic.type_var.bind(resolved_type); } } @@ -1756,7 +1770,8 @@ impl<'context> Elaborator<'context> { let generics = self.add_generics(&alias.type_alias_def.generics); self.current_item = Some(DependencyId::Alias(alias_id)); - let typ = self.use_type(alias.type_alias_def.typ); + let wildcard_allowed = false; + let typ = self.use_type(alias.type_alias_def.typ, wildcard_allowed); if visibility != ItemVisibility::Private { self.check_type_is_not_more_private_then_item(name, visibility, &typ, location); @@ -1966,11 +1981,16 @@ impl<'context> Elaborator<'context> { let struct_def = this.interner.get_type(struct_id); this.add_existing_generics(&unresolved.generics, &struct_def.borrow().generics); + let wildcard_allowed = false; let fields = vecmap(&unresolved.fields, |field| { let ident = &field.item.name; let typ = &field.item.typ; let visibility = field.item.visibility; - StructField { visibility, name: ident.clone(), typ: this.resolve_type(typ.clone()) } + StructField { + visibility, + name: ident.clone(), + typ: this.resolve_type(typ.clone(), wildcard_allowed), + } }); this.resolving_ids.remove(&struct_id); @@ -2001,10 +2021,12 @@ impl<'context> Elaborator<'context> { datatype.borrow_mut().init_variants(); self.resolving_ids.insert(*type_id); + let wildcard_allowed = false; for (i, variant) in typ.enum_def.variants.iter().enumerate() { let parameters = variant.item.parameters.as_ref(); - let types = - parameters.map(|params| vecmap(params, |typ| self.resolve_type(typ.clone()))); + let types = parameters.map(|params| { + vecmap(params, |typ| self.resolve_type(typ.clone(), wildcard_allowed)) + }); let name = variant.item.name.clone(); let is_function = types.is_some(); @@ -2128,7 +2150,8 @@ impl<'context> Elaborator<'context> { for (generics, _, function_set) in function_sets { self.add_generics(generics); - let self_type = self.resolve_type(self_type.clone()); + let wildcard_allowed = false; + let self_type = self.resolve_type(self_type.clone(), wildcard_allowed); function_set.self_type = Some(self_type.clone()); self.self_type = Some(self_type); @@ -2287,7 +2310,8 @@ impl<'context> Elaborator<'context> { .chain(new_generics_trait_constraints.iter().map(|(constraint, _)| constraint)), ); - let self_type = self.resolve_type(unresolved_type); + let wildcard_allowed = false; + let self_type = self.resolve_type(unresolved_type, wildcard_allowed); self.self_type = Some(self_type.clone()); trait_impl.methods.self_type = Some(self_type); diff --git a/compiler/noirc_frontend/src/elaborator/patterns.rs b/compiler/noirc_frontend/src/elaborator/patterns.rs index d1f83b04b82..18312dbf6db 100644 --- a/compiler/noirc_frontend/src/elaborator/patterns.rs +++ b/compiler/noirc_frontend/src/elaborator/patterns.rs @@ -725,7 +725,8 @@ impl Elaborator<'_> { let generics = segment.generics.map(|generics| { vecmap(generics, |generic| { let location = generic.location; - let typ = self.use_type_with_kind(generic, &Kind::Any); + let wildcard_allowed = true; + let typ = self.use_type_with_kind(generic, &Kind::Any, wildcard_allowed); Located::from(location, typ) }) }); @@ -1142,7 +1143,8 @@ impl Elaborator<'_> { pub(super) fn elaborate_type_path(&mut self, path: TypePath) -> (ExprId, Type) { let typ_location = path.typ.location; let turbofish = path.turbofish; - let typ = self.use_type(path.typ); + let wildcard_allowed = true; + let typ = self.use_type(path.typ, wildcard_allowed); self.elaborate_type_path_impl(typ, path.item, turbofish, typ_location) } diff --git a/compiler/noirc_frontend/src/elaborator/primitive_types.rs b/compiler/noirc_frontend/src/elaborator/primitive_types.rs index 7c49df2de15..bdb9cd6fd4b 100644 --- a/compiler/noirc_frontend/src/elaborator/primitive_types.rs +++ b/compiler/noirc_frontend/src/elaborator/primitive_types.rs @@ -185,6 +185,7 @@ impl Elaborator<'_> { primitive_type: PrimitiveType, args: GenericTypeArgs, location: Location, + wildcard_allowed: bool, ) -> Type { match primitive_type { PrimitiveType::Bool @@ -231,6 +232,7 @@ impl Elaborator<'_> { item, location, PathResolutionMode::MarkAsReferenced, + wildcard_allowed, ); assert_eq!(args.len(), 1); let length = args.pop().unwrap(); @@ -243,6 +245,7 @@ impl Elaborator<'_> { item, location, PathResolutionMode::MarkAsReferenced, + wildcard_allowed, ); assert_eq!(args.len(), 2); let element = args.pop().unwrap(); diff --git a/compiler/noirc_frontend/src/elaborator/trait_impls.rs b/compiler/noirc_frontend/src/elaborator/trait_impls.rs index 6bd006b10d5..cf639944c93 100644 --- a/compiler/noirc_frontend/src/elaborator/trait_impls.rs +++ b/compiler/noirc_frontend/src/elaborator/trait_impls.rs @@ -248,7 +248,8 @@ impl Elaborator<'_> { ) -> Vec<(Ident, UnresolvedType, Kind)> { let mut associated_types = Vec::new(); for (name, typ, expr) in trait_impl.associated_constants.drain(..) { - let resolved_type = self.resolve_type(typ); + let wildcard_allowed = false; + let resolved_type = self.resolve_type(typ, wildcard_allowed); let kind = Kind::Numeric(Box::new(resolved_type)); let location = expr.location; let typ = match UnresolvedTypeExpression::from_expr(expr, location) { diff --git a/compiler/noirc_frontend/src/elaborator/types.rs b/compiler/noirc_frontend/src/elaborator/types.rs index 6a61009d259..88f8c359568 100644 --- a/compiler/noirc_frontend/src/elaborator/types.rs +++ b/compiler/noirc_frontend/src/elaborator/types.rs @@ -60,16 +60,26 @@ pub(super) enum TraitPathResolutionMethod { } impl Elaborator<'_> { - pub(crate) fn resolve_type(&mut self, typ: UnresolvedType) -> Type { - self.resolve_type_inner(typ, &Kind::Normal, PathResolutionMode::MarkAsReferenced) + pub(crate) fn resolve_type(&mut self, typ: UnresolvedType, wildcard_allowed: bool) -> Type { + self.resolve_type_inner( + typ, + &Kind::Normal, + PathResolutionMode::MarkAsReferenced, + wildcard_allowed, + ) } - pub(crate) fn use_type(&mut self, typ: UnresolvedType) -> Type { - self.use_type_with_kind(typ, &Kind::Normal) + pub(crate) fn use_type(&mut self, typ: UnresolvedType, wildcard_allowed: bool) -> Type { + self.use_type_with_kind(typ, &Kind::Normal, wildcard_allowed) } - pub(crate) fn use_type_with_kind(&mut self, typ: UnresolvedType, kind: &Kind) -> Type { - self.resolve_type_inner(typ, kind, PathResolutionMode::MarkAsUsed) + pub(crate) fn use_type_with_kind( + &mut self, + typ: UnresolvedType, + kind: &Kind, + wildcard_allowed: bool, + ) -> Type { + self.resolve_type_inner(typ, kind, PathResolutionMode::MarkAsUsed, wildcard_allowed) } /// Translates an UnresolvedType to a Type with a `TypeKind::Normal` @@ -78,17 +88,28 @@ impl Elaborator<'_> { typ: UnresolvedType, kind: &Kind, mode: PathResolutionMode, + wildcard_allowed: bool, ) -> Type { let location = typ.location; - let resolved_type = self.resolve_type_with_kind_inner(typ, kind, mode); + let resolved_type = self.resolve_type_with_kind_inner(typ, kind, mode, wildcard_allowed); if resolved_type.is_nested_slice() { self.push_err(ResolverError::NestedSlices { location }); } resolved_type } - pub(crate) fn resolve_type_with_kind(&mut self, typ: UnresolvedType, kind: &Kind) -> Type { - self.resolve_type_with_kind_inner(typ, kind, PathResolutionMode::MarkAsReferenced) + pub(crate) fn resolve_type_with_kind( + &mut self, + typ: UnresolvedType, + kind: &Kind, + wildcard_allowed: bool, + ) -> Type { + self.resolve_type_with_kind_inner( + typ, + kind, + PathResolutionMode::MarkAsReferenced, + wildcard_allowed, + ) } /// Translates an UnresolvedType into a Type and appends any @@ -98,6 +119,7 @@ impl Elaborator<'_> { typ: UnresolvedType, kind: &Kind, mode: PathResolutionMode, + wildcard_allowed: bool, ) -> Type { use crate::ast::UnresolvedTypeData::*; @@ -115,15 +137,28 @@ impl Elaborator<'_> { let resolved_type = match typ.typ { Array(size, elem) => { - let elem = Box::new(self.resolve_type_with_kind_inner(*elem, kind, mode)); - let size = self.convert_expression_type(size, &Kind::u32(), location); + let elem = Box::new(self.resolve_type_with_kind_inner( + *elem, + kind, + mode, + wildcard_allowed, + )); + let size = + self.convert_expression_type(size, &Kind::u32(), location, wildcard_allowed); Type::Array(Box::new(size), elem) } Slice(elem) => { - let elem = Box::new(self.resolve_type_with_kind_inner(*elem, kind, mode)); + let elem = Box::new(self.resolve_type_with_kind_inner( + *elem, + kind, + mode, + wildcard_allowed, + )); Type::Slice(elem) } - Expression(expr) => self.convert_expression_type(expr, kind, location), + Expression(expr) => { + self.convert_expression_type(expr, kind, location, wildcard_allowed) + } Unit => Type::Unit, Unspecified => { let location = typ.location; @@ -133,7 +168,7 @@ impl Elaborator<'_> { Error => Type::Error, Named(path, args, _) => { let path = self.validate_path(path); - self.resolve_named_type(path, args, mode) + self.resolve_named_type(path, args, mode, wildcard_allowed) } TraitAsType(path, args) => { let path = self.validate_path(path); @@ -141,14 +176,18 @@ impl Elaborator<'_> { } Tuple(fields) => Type::Tuple(vecmap(fields, |field| { - self.resolve_type_with_kind_inner(field, kind, mode) + self.resolve_type_with_kind_inner(field, kind, mode, wildcard_allowed) })), Function(args, ret, env, unconstrained) => { - let args = vecmap(args, |arg| self.resolve_type_with_kind_inner(arg, kind, mode)); - let ret = Box::new(self.resolve_type_with_kind_inner(*ret, kind, mode)); + let args = vecmap(args, |arg| { + self.resolve_type_with_kind_inner(arg, kind, mode, wildcard_allowed) + }); + let ret = + Box::new(self.resolve_type_with_kind_inner(*ret, kind, mode, wildcard_allowed)); let env_location = env.location; - let env = Box::new(self.resolve_type_with_kind_inner(*env, kind, mode)); + let env = + Box::new(self.resolve_type_with_kind_inner(*env, kind, mode, wildcard_allowed)); match *env { Type::Unit | Type::Tuple(_) | Type::NamedGeneric(_) => { @@ -168,19 +207,27 @@ impl Elaborator<'_> { self.use_unstable_feature(UnstableFeature::Ownership, location); } Type::Reference( - Box::new(self.resolve_type_with_kind_inner(*element, kind, mode)), + Box::new(self.resolve_type_with_kind_inner( + *element, + kind, + mode, + wildcard_allowed, + )), mutable, ) } - Parenthesized(typ) => self.resolve_type_with_kind_inner(*typ, kind, mode), + Parenthesized(typ) => { + self.resolve_type_with_kind_inner(*typ, kind, mode, wildcard_allowed) + } Resolved(id) => self.interner.get_quoted_type(id).clone(), - AsTraitPath(path) => self.resolve_as_trait_path(*path), + AsTraitPath(path) => self.resolve_as_trait_path(*path, wildcard_allowed), Interned(id) => { let typ = self.interner.get_unresolved_type_data(id).clone(); return self.resolve_type_with_kind_inner( UnresolvedType { typ, location }, kind, mode, + wildcard_allowed, ); } }; @@ -236,6 +283,7 @@ impl Elaborator<'_> { path: TypedPath, args: GenericTypeArgs, mode: PathResolutionMode, + wildcard_allowed: bool, ) -> Type { if args.is_empty() { if let Some(typ) = self.lookup_generic_or_global_type(&path, mode) { @@ -245,7 +293,7 @@ impl Elaborator<'_> { // Check if the path is a type variable first. We currently disallow generics on type // variables since we do not support higher-kinded types. - if let Some(typ) = self.lookup_type_variable(&path, &args) { + if let Some(typ) = self.lookup_type_variable(&path, &args, wildcard_allowed) { return typ; } @@ -253,7 +301,8 @@ impl Elaborator<'_> { if let Some(type_alias) = self.lookup_type_alias(path.clone(), mode) { let id = type_alias.borrow().id; - let (args, _) = self.resolve_type_args_inner(args, id, location, mode); + let (args, _) = + self.resolve_type_args_inner(args, id, location, mode, wildcard_allowed); if let Some(item) = self.current_item { self.interner.add_type_alias_dependency(item, id); @@ -296,8 +345,13 @@ impl Elaborator<'_> { }); } - let (args, _) = - self.resolve_type_args_inner(args, data_type.borrow(), location, mode); + let (args, _) = self.resolve_type_args_inner( + args, + data_type.borrow(), + location, + mode, + wildcard_allowed, + ); if let Some(current_item) = self.current_item { let dependency_id = data_type.borrow().id; @@ -307,7 +361,12 @@ impl Elaborator<'_> { Type::DataType(data_type, args) } Ok(PathResolutionItem::PrimitiveType(primitive_type)) => { - let typ = self.instantiate_primitive_type(primitive_type, args, location); + let typ = self.instantiate_primitive_type( + primitive_type, + args, + location, + wildcard_allowed, + ); if let Type::Quoted(quoted) = typ { let in_function = matches!(self.current_item, Some(DependencyId::Function(_))); if in_function && !self.in_comptime_context() { @@ -346,7 +405,12 @@ impl Elaborator<'_> { } } - fn lookup_type_variable(&mut self, path: &TypedPath, args: &GenericTypeArgs) -> Option { + fn lookup_type_variable( + &mut self, + path: &TypedPath, + args: &GenericTypeArgs, + wildcard_allowed: bool, + ) -> Option { if path.segments.len() != 1 { return None; } @@ -360,7 +424,15 @@ impl Elaborator<'_> { } Some(self_type) } - WILDCARD_TYPE => Some(self.interner.next_type_variable_with_kind(Kind::Any)), + WILDCARD_TYPE => { + if !wildcard_allowed { + self.push_err(ResolverError::WildcardTypeDisallowed { + location: path.location, + }); + } + + Some(self.interner.next_type_variable_with_kind(Kind::Any)) + } _ => None, } } @@ -377,7 +449,9 @@ impl Elaborator<'_> { let trait_as_type_info = self.lookup_trait_or_error(path).map(|t| t.id); if let Some(id) = trait_as_type_info { - let (ordered, named) = self.resolve_type_args_inner(args, id, location, mode); + let wildcard_allowed = false; + let (ordered, named) = + self.resolve_type_args_inner(args, id, location, mode, wildcard_allowed); let name = self.interner.get_trait(id).name.to_string(); let generics = TraitGenerics { ordered, named }; Type::TraitAsType(id, Rc::new(name), generics) @@ -395,7 +469,16 @@ impl Elaborator<'_> { location: Location, ) -> (Vec, Vec) { let mode = PathResolutionMode::MarkAsReferenced; - self.resolve_type_or_trait_args_inner(args, item, location, false, mode) + let allow_implicit_named_args = false; + let wildcard_allowed = true; + self.resolve_type_or_trait_args_inner( + args, + item, + location, + allow_implicit_named_args, + mode, + wildcard_allowed, + ) } pub(super) fn use_type_args( @@ -405,7 +488,8 @@ impl Elaborator<'_> { location: Location, ) -> (Vec, Vec) { let mode = PathResolutionMode::MarkAsUsed; - self.resolve_type_args_inner(args, item, location, mode) + let wildcard_allowed = true; + self.resolve_type_args_inner(args, item, location, mode, wildcard_allowed) } pub(super) fn resolve_type_args_inner( @@ -414,8 +498,17 @@ impl Elaborator<'_> { item: impl Generic, location: Location, mode: PathResolutionMode, + wildcard_allowed: bool, ) -> (Vec, Vec) { - self.resolve_type_or_trait_args_inner(args, item, location, true, mode) + let allow_implicit_named_args = true; + self.resolve_type_or_trait_args_inner( + args, + item, + location, + allow_implicit_named_args, + mode, + wildcard_allowed, + ) } pub(super) fn resolve_type_or_trait_args_inner( @@ -425,6 +518,7 @@ impl Elaborator<'_> { location: Location, allow_implicit_named_args: bool, mode: PathResolutionMode, + wildcard_allowed: bool, ) -> (Vec, Vec) { let expected_kinds = item.generic_kinds(self.interner); @@ -440,8 +534,9 @@ impl Elaborator<'_> { } let ordered_args = expected_kinds.iter().zip(args.ordered_args); - let ordered = - vecmap(ordered_args, |(kind, typ)| self.resolve_type_with_kind_inner(typ, kind, mode)); + let ordered = vecmap(ordered_args, |(kind, typ)| { + self.resolve_type_with_kind_inner(typ, kind, mode, wildcard_allowed) + }); let mut associated = Vec::new(); @@ -452,6 +547,7 @@ impl Elaborator<'_> { location, allow_implicit_named_args, mode, + wildcard_allowed, ); } else if !args.named_args.is_empty() { let item_kind = item.item_kind(); @@ -468,6 +564,7 @@ impl Elaborator<'_> { location: Location, allow_implicit_named_args: bool, mode: PathResolutionMode, + wildcard_allowed: bool, ) -> Vec { let mut seen_args = HashMap::default(); let mut required_args = item.named_generics(self.interner); @@ -492,7 +589,8 @@ impl Elaborator<'_> { let expected = required_args.remove(index); seen_args.insert(name.to_string(), name.location()); - let typ = self.resolve_type_with_kind_inner(typ, &expected.kind(), mode); + let typ = + self.resolve_type_with_kind_inner(typ, &expected.kind(), mode, wildcard_allowed); resolved.push(NamedType { name, typ }); } @@ -603,12 +701,18 @@ impl Elaborator<'_> { length: UnresolvedTypeExpression, expected_kind: &Kind, location: Location, + wildcard_allowed: bool, ) -> Type { match length { UnresolvedTypeExpression::Variable(path) => { let path = self.validate_path(path); let mode = PathResolutionMode::MarkAsReferenced; - let typ = self.resolve_named_type(path, GenericTypeArgs::default(), mode); + let typ = self.resolve_named_type( + path, + GenericTypeArgs::default(), + mode, + wildcard_allowed, + ); self.check_kind(typ, expected_kind, location) } UnresolvedTypeExpression::Constant(int, suffix, _span) => { @@ -619,8 +723,18 @@ impl Elaborator<'_> { } UnresolvedTypeExpression::BinaryOperation(lhs, op, rhs, location) => { let (lhs_location, rhs_location) = (lhs.location(), rhs.location()); - let lhs = self.convert_expression_type(*lhs, expected_kind, lhs_location); - let rhs = self.convert_expression_type(*rhs, expected_kind, rhs_location); + let lhs = self.convert_expression_type( + *lhs, + expected_kind, + lhs_location, + wildcard_allowed, + ); + let rhs = self.convert_expression_type( + *rhs, + expected_kind, + rhs_location, + wildcard_allowed, + ); match (lhs, rhs) { (Type::Constant(lhs, lhs_kind), Type::Constant(rhs, rhs_kind)) => { @@ -651,7 +765,7 @@ impl Elaborator<'_> { } } UnresolvedTypeExpression::AsTraitPath(path) => { - let typ = self.resolve_as_trait_path(*path); + let typ = self.resolve_as_trait_path(*path, wildcard_allowed); self.check_kind(typ, expected_kind, location) } } @@ -674,7 +788,7 @@ impl Elaborator<'_> { typ } - fn resolve_as_trait_path(&mut self, path: AsTraitPath) -> Type { + fn resolve_as_trait_path(&mut self, path: AsTraitPath, wildcard_allowed: bool) -> Type { let location = path.trait_path.location; let trait_path = self.validate_path(path.trait_path.clone()); let Some(trait_id) = self.resolve_trait_by_path(trait_path) else { @@ -683,7 +797,7 @@ impl Elaborator<'_> { }; let (ordered, named) = self.use_type_args(path.trait_generics.clone(), trait_id, location); - let object_type = self.use_type(path.typ.clone()); + let object_type = self.use_type(path.typ.clone(), wildcard_allowed); match self.interner.lookup_trait_implementation(&object_type, trait_id, &ordered, &named) { Ok((impl_kind, instantiation_bindings)) => { @@ -989,7 +1103,10 @@ impl Elaborator<'_> { UnresolvedTypeData::Unspecified => { self.interner.next_type_variable_with_kind(Kind::Any) } - _ => self.use_type(typ), + _ => { + let wildcard_allowed = true; + self.use_type(typ, wildcard_allowed) + } } } diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 3ea5e5aa2f6..faeb45ba7ec 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -896,9 +896,10 @@ fn quoted_as_type( let argument = check_one_argument(arguments, location)?; let typ = parse(interpreter.elaborator, argument, Parser::parse_type_or_error, "a type")?; let reason = Some(ElaborateReason::EvaluatingComptimeCall("Quoted::as_type", location)); + let wildcard_allowed = false; let typ = interpreter.elaborate_in_function(interpreter.current_function, reason, |elaborator| { - elaborator.use_type(typ) + elaborator.use_type(typ, wildcard_allowed) }); Ok(Value::Type(typ)) } diff --git a/compiler/noirc_frontend/src/hir/resolution/errors.rs b/compiler/noirc_frontend/src/hir/resolution/errors.rs index 2fe80989f69..a72789d79de 100644 --- a/compiler/noirc_frontend/src/hir/resolution/errors.rs +++ b/compiler/noirc_frontend/src/hir/resolution/errors.rs @@ -182,6 +182,8 @@ pub enum ResolverError { AssociatedItemConstraintsNotAllowedInGenerics { location: Location }, #[error("Ambiguous associated type")] AmbiguousAssociatedType { trait_name: String, associated_type_name: String, location: Location }, + #[error("The placeholder `_` is not allowed within types on item signatures for functions")] + WildcardTypeDisallowed { location: Location }, } impl ResolverError { @@ -243,7 +245,8 @@ impl ResolverError { | ResolverError::LowLevelFunctionOutsideOfStdlib { location } | ResolverError::UnreachableStatement { location, .. } | ResolverError::AssociatedItemConstraintsNotAllowedInGenerics { location } - | ResolverError::AmbiguousAssociatedType { location, .. } => *location, + | ResolverError::AmbiguousAssociatedType { location, .. } + | ResolverError::WildcardTypeDisallowed { location } => *location, ResolverError::UnusedVariable { ident } | ResolverError::UnusedItem { ident, .. } | ResolverError::DuplicateField { field: ident } @@ -768,6 +771,13 @@ impl<'a> From<&'a ResolverError> for Diagnostic { *location, ) } + ResolverError::WildcardTypeDisallowed { location } => { + Diagnostic::simple_error( + "The placeholder `_` is not allowed within types on item signatures for functions".to_string(), + String::new(), + *location, + ) + } } } } diff --git a/test_programs/compile_failure/wildcards_in_wrong_places/Nargo.toml b/test_programs/compile_failure/wildcards_in_wrong_places/Nargo.toml new file mode 100644 index 00000000000..1bc93fc8026 --- /dev/null +++ b/test_programs/compile_failure/wildcards_in_wrong_places/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "wildcards_in_wrong_places" +type = "bin" +authors = [""] +compiler_version = ">=0.33.0" + +[dependencies] diff --git a/test_programs/compile_failure/wildcards_in_wrong_places/src/main.nr b/test_programs/compile_failure/wildcards_in_wrong_places/src/main.nr new file mode 100644 index 00000000000..a71d64d0734 --- /dev/null +++ b/test_programs/compile_failure/wildcards_in_wrong_places/src/main.nr @@ -0,0 +1,19 @@ +pub fn foo(_: [_; _]) -> [_; _] { + [1] +} + +pub struct Foo { + x: [_; _], +} + +impl Foo { + fn foo(_: [_; _]) -> [_; _] { + [1] + } +} + +pub trait Trait { + fn trait_method(_: [_; _]) -> [_; _]; +} + +fn main() {} diff --git a/tooling/nargo_cli/tests/snapshots/compile_failure/wildcards_in_wrong_places/execute__tests__stderr.snap b/tooling/nargo_cli/tests/snapshots/compile_failure/wildcards_in_wrong_places/execute__tests__stderr.snap new file mode 100644 index 00000000000..e799688c31e --- /dev/null +++ b/tooling/nargo_cli/tests/snapshots/compile_failure/wildcards_in_wrong_places/execute__tests__stderr.snap @@ -0,0 +1,103 @@ +--- +source: tooling/nargo_cli/tests/execute.rs +expression: stderr +--- +error: The placeholder `_` is not allowed within types on item signatures for functions + ┌─ src/main.nr:6:9 + │ +6 │ x: [_; _], + │ - + │ + +error: The placeholder `_` is not allowed within types on item signatures for functions + ┌─ src/main.nr:6:12 + │ +6 │ x: [_; _], + │ - + │ + +error: The placeholder `_` is not allowed within types on item signatures for functions + ┌─ src/main.nr:1:16 + │ +1 │ pub fn foo(_: [_; _]) -> [_; _] { + │ - + │ + +error: The placeholder `_` is not allowed within types on item signatures for functions + ┌─ src/main.nr:1:19 + │ +1 │ pub fn foo(_: [_; _]) -> [_; _] { + │ - + │ + +error: The placeholder `_` is not allowed within types on item signatures for functions + ┌─ src/main.nr:1:27 + │ +1 │ pub fn foo(_: [_; _]) -> [_; _] { + │ - + │ + +error: The placeholder `_` is not allowed within types on item signatures for functions + ┌─ src/main.nr:1:30 + │ +1 │ pub fn foo(_: [_; _]) -> [_; _] { + │ - + │ + +error: The placeholder `_` is not allowed within types on item signatures for functions + ┌─ src/main.nr:10:16 + │ +10 │ fn foo(_: [_; _]) -> [_; _] { + │ - + │ + +error: The placeholder `_` is not allowed within types on item signatures for functions + ┌─ src/main.nr:10:19 + │ +10 │ fn foo(_: [_; _]) -> [_; _] { + │ - + │ + +error: The placeholder `_` is not allowed within types on item signatures for functions + ┌─ src/main.nr:10:27 + │ +10 │ fn foo(_: [_; _]) -> [_; _] { + │ - + │ + +error: The placeholder `_` is not allowed within types on item signatures for functions + ┌─ src/main.nr:10:30 + │ +10 │ fn foo(_: [_; _]) -> [_; _] { + │ - + │ + +error: The placeholder `_` is not allowed within types on item signatures for functions + ┌─ src/main.nr:16:25 + │ +16 │ fn trait_method(_: [_; _]) -> [_; _]; + │ - + │ + +error: The placeholder `_` is not allowed within types on item signatures for functions + ┌─ src/main.nr:16:28 + │ +16 │ fn trait_method(_: [_; _]) -> [_; _]; + │ - + │ + +error: The placeholder `_` is not allowed within types on item signatures for functions + ┌─ src/main.nr:16:36 + │ +16 │ fn trait_method(_: [_; _]) -> [_; _]; + │ - + │ + +error: The placeholder `_` is not allowed within types on item signatures for functions + ┌─ src/main.nr:16:39 + │ +16 │ fn trait_method(_: [_; _]) -> [_; _]; + │ - + │ + +Aborting due to 14 previous errors