Skip to content

Commit

Permalink
fix: distinguish TypePath with and without turbofish (#6404)
Browse files Browse the repository at this point in the history
  • Loading branch information
asterite authored Oct 30, 2024
1 parent 3a073f7 commit 0e974c2
Show file tree
Hide file tree
Showing 8 changed files with 23 additions and 16 deletions.
4 changes: 2 additions & 2 deletions compiler/noirc_frontend/src/ast/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -802,8 +802,8 @@ impl Display for AsTraitPath {
impl Display for TypePath {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}::{}", self.typ, self.item)?;
if !self.turbofish.is_empty() {
write!(f, "::{}", self.turbofish)?;
if let Some(turbofish) = &self.turbofish {
write!(f, "::{}", turbofish)?;
}
Ok(())
}
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 @@ -408,7 +408,7 @@ pub struct AsTraitPath {
pub struct TypePath {
pub typ: UnresolvedType,
pub item: Ident,
pub turbofish: GenericTypeArgs,
pub turbofish: Option<GenericTypeArgs>,
}

// Note: Path deliberately doesn't implement Recoverable.
Expand Down
4 changes: 3 additions & 1 deletion compiler/noirc_frontend/src/ast/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1245,7 +1245,9 @@ impl TypePath {

pub fn accept_children(&self, visitor: &mut impl Visitor) {
self.typ.accept(visitor);
self.turbofish.accept(visitor);
if let Some(turbofish) = &self.turbofish {
turbofish.accept(visitor);
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions compiler/noirc_frontend/src/elaborator/patterns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -762,8 +762,8 @@ impl<'context> Elaborator<'context> {
.func_id(self.interner)
.expect("Expected trait function to be a DefinitionKind::Function");

let generics = self.resolve_type_args(path.turbofish, func_id, span).0;
let generics = (!generics.is_empty()).then_some(generics);
let generics =
path.turbofish.map(|turbofish| self.resolve_type_args(turbofish, func_id, span).0);

let location = Location::new(span, self.file);
let id = self.interner.function_definition_id(func_id);
Expand Down
4 changes: 3 additions & 1 deletion compiler/noirc_frontend/src/hir/comptime/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -620,7 +620,9 @@ fn remove_interned_in_expression_kind(
}
ExpressionKind::TypePath(mut path) => {
path.typ = remove_interned_in_unresolved_type(interner, path.typ);
path.turbofish = remove_interned_in_generic_type_args(interner, path.turbofish);
path.turbofish = path
.turbofish
.map(|turbofish| remove_interned_in_generic_type_args(interner, turbofish));
ExpressionKind::TypePath(path)
}
ExpressionKind::Resolved(id) => {
Expand Down
12 changes: 5 additions & 7 deletions compiler/noirc_frontend/src/parser/parser/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use noirc_errors::Span;
use crate::{
ast::{
ArrayLiteral, BlockExpression, CallExpression, CastExpression, ConstructorExpression,
Expression, ExpressionKind, GenericTypeArgs, Ident, IfExpression, IndexExpression, Literal,
Expression, ExpressionKind, Ident, IfExpression, IndexExpression, Literal,
MemberAccessExpression, MethodCallExpression, Statement, TypePath, UnaryOp, UnresolvedType,
},
parser::{labels::ParsingRuleLabel, parser::parse_many::separated_by_comma, ParserErrorReason},
Expand Down Expand Up @@ -548,15 +548,13 @@ impl<'a> Parser<'a> {
Ident::new(String::new(), self.span_at_previous_token_end())
};

let turbofish = if self.eat_double_colon() {
let turbofish = self.eat_double_colon().then(|| {
let generics = self.parse_generic_type_args();
if generics.is_empty() {
self.expected_token(Token::Less);
}
generics
} else {
GenericTypeArgs::default()
};
});

Some(ExpressionKind::TypePath(TypePath { typ, item, turbofish }))
}
Expand Down Expand Up @@ -1587,7 +1585,7 @@ mod tests {
};
assert_eq!(type_path.typ.to_string(), "Field");
assert_eq!(type_path.item.to_string(), "foo");
assert!(type_path.turbofish.is_empty());
assert!(type_path.turbofish.is_none());
}

#[test]
Expand All @@ -1599,7 +1597,7 @@ mod tests {
};
assert_eq!(type_path.typ.to_string(), "Field");
assert_eq!(type_path.item.to_string(), "foo");
assert!(!type_path.turbofish.is_empty());
assert!(type_path.turbofish.is_some());
}

#[test]
Expand Down
5 changes: 5 additions & 0 deletions test_programs/compile_success_empty/type_path/src/main.nr
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ fn main() {
$foo::static()
}
}

// Make sure this call works fine: in the past we used to not distinguish
// whether a TypePath had generics or not, always resolved them, filling them
// up with Type::Error, and eventually leading to an ICE.
let _ = Field::from_be_bytes([1]);
}

pub struct Foo {}
Expand Down
4 changes: 2 additions & 2 deletions tooling/nargo_fmt/src/formatter/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,9 +382,9 @@ impl<'a, 'b> ChunkFormatter<'a, 'b> {
formatter.format_type(type_path.typ);
formatter.write_token(Token::DoubleColon);
formatter.write_identifier(type_path.item);
if !type_path.turbofish.is_empty() {
if let Some(turbofish) = type_path.turbofish {
formatter.write_token(Token::DoubleColon);
formatter.format_generic_type_args(type_path.turbofish);
formatter.format_generic_type_args(turbofish);
}
}));
group
Expand Down

0 comments on commit 0e974c2

Please sign in to comment.