-
Notifications
You must be signed in to change notification settings - Fork 260
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
feat: type alias for numeric generics #7583
base: master
Are you sure you want to change the base?
Changes from all commits
a1b9b69
0c2f4ff
82d639e
ff24516
4d4dabe
531467a
8f50d5e
249f71b
ca3298f
7884d9f
e19f7e3
6739cc9
7b79b8a
c5e1dcc
0074169
44abde3
e04ad34
97b7063
faf9f0c
efcecff
e1552b4
a4ae121
e5de933
7522b3a
fd35270
fc7b048
58b39a9
1744fea
3eb7c2f
cb8d263
44cd174
d67a9cb
fcc9c04
49d865f
fb837af
afa5cc9
02fe712
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,7 @@ mod traits; | |
mod type_alias; | ||
mod visitor; | ||
|
||
use noirc_errors::Located; | ||
use noirc_errors::Location; | ||
pub use visitor::AttributeTarget; | ||
pub use visitor::Visitor; | ||
|
@@ -33,6 +34,7 @@ pub use structure::*; | |
pub use traits::*; | ||
pub use type_alias::*; | ||
|
||
use crate::signed_field::SignedField; | ||
use crate::{ | ||
BinaryTypeOperator, | ||
node_interner::{InternedUnresolvedTypeData, QuotedTypeId}, | ||
|
@@ -450,6 +452,21 @@ impl UnresolvedTypeData { | |
| UnresolvedTypeData::Error => false, | ||
} | ||
} | ||
|
||
pub(crate) fn try_into_expression(&self) -> Option<UnresolvedTypeExpression> { | ||
match self { | ||
UnresolvedTypeData::Expression(expr) => Some(expr.clone()), | ||
UnresolvedTypeData::Parenthesized(unresolved_type) => { | ||
unresolved_type.typ.try_into_expression() | ||
} | ||
UnresolvedTypeData::Named(path, generics, _) | ||
if path.is_ident() && generics.is_empty() => | ||
{ | ||
Some(UnresolvedTypeExpression::Variable(path.clone())) | ||
} | ||
_ => None, | ||
} | ||
} | ||
} | ||
|
||
impl UnresolvedTypeExpression { | ||
|
@@ -530,6 +547,38 @@ impl UnresolvedTypeExpression { | |
} | ||
} | ||
|
||
pub fn to_expression_kind(&self) -> ExpressionKind { | ||
match self { | ||
UnresolvedTypeExpression::Variable(path) => ExpressionKind::Variable(path.clone()), | ||
UnresolvedTypeExpression::Constant(int, _) => { | ||
ExpressionKind::Literal(Literal::Integer(SignedField { | ||
field: *int, | ||
is_negative: false, | ||
})) | ||
} | ||
UnresolvedTypeExpression::BinaryOperation(lhs, op, rhs, location) => { | ||
ExpressionKind::Infix(Box::new(InfixExpression { | ||
lhs: Expression { kind: lhs.to_expression_kind(), location: *location }, | ||
operator: Located::from(*location, Self::operator_to_binary_op_kind_helper(op)), | ||
rhs: Expression { kind: rhs.to_expression_kind(), location: *location }, | ||
})) | ||
} | ||
UnresolvedTypeExpression::AsTraitPath(path) => { | ||
ExpressionKind::AsTraitPath(*path.clone()) | ||
} | ||
} | ||
} | ||
|
||
fn operator_to_binary_op_kind_helper(op: &BinaryTypeOperator) -> BinaryOpKind { | ||
match op { | ||
BinaryTypeOperator::Addition => BinaryOpKind::Add, | ||
BinaryTypeOperator::Subtraction => BinaryOpKind::Subtract, | ||
BinaryTypeOperator::Multiplication => BinaryOpKind::Multiply, | ||
BinaryTypeOperator::Division => BinaryOpKind::Divide, | ||
BinaryTypeOperator::Modulo => BinaryOpKind::Modulo, | ||
} | ||
} | ||
|
||
fn operator_allowed(op: BinaryOpKind) -> bool { | ||
matches!( | ||
op, | ||
|
@@ -553,6 +602,17 @@ impl UnresolvedTypeExpression { | |
} | ||
} | ||
} | ||
|
||
pub(crate) fn is_valid_expression(&self) -> bool { | ||
match self { | ||
UnresolvedTypeExpression::Variable(path) => path.is_ident(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The comment in elaborator/mod.rs mentions this function should allow globals & constants. We can have multiple segment paths that still resolve to constants or globals. E.g. |
||
UnresolvedTypeExpression::Constant(_, _) => true, | ||
UnresolvedTypeExpression::BinaryOperation(lhs, _, rhs, _) => { | ||
lhs.is_valid_expression() && rhs.is_valid_expression() | ||
} | ||
UnresolvedTypeExpression::AsTraitPath(_) => true, | ||
} | ||
} | ||
} | ||
|
||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,7 @@ use crate::{ | |
DataType, Kind, Shared, Type, TypeAlias, TypeBindings, | ||
ast::{ | ||
ERROR_IDENT, Expression, ExpressionKind, Ident, ItemVisibility, Path, Pattern, TypePath, | ||
UnresolvedType, | ||
UnresolvedType, UnresolvedTypeExpression, | ||
}, | ||
hir::{ | ||
def_collector::dc_crate::CompilationError, | ||
|
@@ -537,11 +537,24 @@ impl Elaborator<'_> { | |
|
||
pub(super) fn elaborate_variable(&mut self, variable: Path) -> (ExprId, Type) { | ||
let unresolved_turbofish = variable.segments.last().unwrap().generics.clone(); | ||
|
||
let location = variable.location; | ||
let (expr, item) = self.resolve_variable(variable); | ||
let definition_id = expr.id; | ||
|
||
if expr.id == DefinitionId::dummy_id() { | ||
if let Some(PathResolutionItem::TypeAlias(alias)) = item { | ||
Comment on lines
+544
to
+545
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the outer |
||
// A type alias to a numeric generics is considered like a variable | ||
// but it is not a real variable so it does not resolve to a valid Identifier | ||
// In order to handle this, we retrieve the numeric generics expression that the type aliases to | ||
let type_alias = self.interner.get_type_alias(alias); | ||
if let Some(expr) = type_alias.borrow().numeric_expr.clone() { | ||
let expr = UnresolvedTypeExpression::to_expression_kind(&expr); | ||
let expr = Expression::new(expr, type_alias.borrow().location); | ||
return self.elaborate_expression(expr); | ||
} | ||
} | ||
} | ||
|
||
let type_generics = item.map(|item| self.resolve_item_turbofish(item)).unwrap_or_default(); | ||
|
||
let definition = self.interner.try_definition(definition_id); | ||
|
@@ -860,6 +873,15 @@ impl Elaborator<'_> { | |
Err(_) => error, | ||
}, | ||
None => match self.lookup_global(path) { | ||
Ok((dummy_id, PathResolutionItem::TypeAlias(type_alias_id))) | ||
if dummy_id == DefinitionId::dummy_id() => | ||
{ | ||
// Allow path which resolves to a type alias | ||
return ( | ||
(HirIdent::non_trait_method(dummy_id, location), 4), | ||
Some(PathResolutionItem::TypeAlias(type_alias_id)), | ||
); | ||
} | ||
Ok((id, item)) => { | ||
return ((HirIdent::non_trait_method(id, location), 0), Some(item)); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -88,14 +88,31 @@ impl Elaborator<'_> { | |
return Ok((self.interner.function_definition_id(function), item)); | ||
} | ||
|
||
if let PathResolutionItem::Global(global) = item { | ||
let global = self.interner.get_global(global); | ||
return Ok((global.definition_id, item)); | ||
} | ||
|
||
let expected = "global variable"; | ||
let got = "local variable"; | ||
Err(ResolverError::Expected { location, expected, got }) | ||
match item { | ||
PathResolutionItem::Global(global) => { | ||
let global = self.interner.get_global(global); | ||
Ok((global.definition_id, item)) | ||
} | ||
PathResolutionItem::TypeAlias(type_alias_id) => { | ||
let type_alias = self.interner.get_type_alias(type_alias_id); | ||
|
||
if type_alias.borrow().numeric_expr.is_some() { | ||
// Type alias to numeric generics are aliases to some global value | ||
// Therefore we allow this case although we cannot provide the value yet | ||
return Ok((DefinitionId::dummy_id(), item)); | ||
Comment on lines
+102
to
+104
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks potentially suspicious - when are these dummy ids filled in? If we assign each numeric type alias a DefinitionId we can probably do away with the dummy ids here. |
||
} | ||
if matches!(type_alias.borrow().typ, Type::Alias(_, _)) | ||
|| matches!(type_alias.borrow().typ, Type::Error) | ||
{ | ||
// Type alias to a type alias is not supported, but the error is handled in define_type_alias() | ||
return Ok((DefinitionId::dummy_id(), item)); | ||
} | ||
Err(ResolverError::Expected { location, expected, got }) | ||
} | ||
_ => Err(ResolverError::Expected { location, expected, got }), | ||
} | ||
} | ||
|
||
pub fn push_scope(&mut self) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -61,6 +61,15 @@ impl Elaborator<'_> { | |
resolved_type | ||
} | ||
|
||
pub(crate) fn resolve_type_with_kind(&mut self, typ: UnresolvedType, kind: &Kind) -> Type { | ||
let location = typ.location; | ||
let resolved_type = self.resolve_type_inner(typ, kind); | ||
if resolved_type.is_nested_slice() { | ||
self.push_err(ResolverError::NestedSlices { location }); | ||
} | ||
resolved_type | ||
} | ||
|
||
Comment on lines
+64
to
+72
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Was this added from this PR? We used to have this method although it looks like it was removed a while back. Just flagging this in case it was the result of a merge and we don't need it any more. |
||
/// Translates an UnresolvedType into a Type and appends any | ||
/// freshly created TypeVariables created to new_variables. | ||
pub fn resolve_type_inner(&mut self, typ: UnresolvedType, kind: &Kind) -> Type { | ||
|
@@ -512,7 +521,17 @@ impl Elaborator<'_> { | |
) -> Type { | ||
match length { | ||
UnresolvedTypeExpression::Variable(path) => { | ||
let typ = self.resolve_named_type(path, GenericTypeArgs::default()); | ||
let mut ab = GenericTypeArgs::default(); | ||
// Use generics from path, if they exist | ||
if let Some(last_segment) = path.segments.last() { | ||
if let Some(generics) = &last_segment.generics { | ||
ab.ordered_args = generics.clone(); | ||
} | ||
} | ||
let mut typ = self.resolve_named_type(path, ab); | ||
if let Type::Alias(alias, vec) = typ { | ||
typ = alias.borrow().get_type(&vec); | ||
} | ||
self.check_kind(typ, expected_kind, location) | ||
} | ||
UnresolvedTypeExpression::Constant(int, _span) => { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be a method on BinaryTypeOperator