Skip to content
Open
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
3 changes: 3 additions & 0 deletions components/dada-ir-ast/src/ast/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ pub enum AstTyKind<'db> {

/// `type T`
GenericDecl(AstGenericDecl<'db>),

/// `(A, B, C)`
Tuple(SpanVec<'db, AstTy<'db>>),
}

#[derive(SalsaSerialize)]
Expand Down
8 changes: 7 additions & 1 deletion components/dada-ir-ast/src/ast/util.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::ops::Deref;
use std::ops::{Deref, DerefMut};

use salsa::Update;
use serde::Serialize;
Expand All @@ -20,6 +20,12 @@ impl<T: Update> Deref for SpanVec<'_, T> {
}
}

impl<T: Update> DerefMut for SpanVec<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.values
}
}

impl<'db, T> IntoIterator for &'db SpanVec<'db, T>
where
T: Update,
Expand Down
4 changes: 4 additions & 0 deletions components/dada-ir-ast/src/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ impl Diagnostic {
Self::new(db, Level::Info, span, message)
}

pub fn warning<'db>(db: &'db dyn crate::Db, span: Span<'db>, message: impl Display) -> Self {
Self::new(db, Level::Warning, span, message)
}

pub fn new<'db>(
db: &'db dyn crate::Db,
level: Level,
Expand Down
12 changes: 12 additions & 0 deletions components/dada-ir-sym/src/check/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,18 @@ impl<'db> CheckInEnv<'db> for AstTy<'db> {
let symbol = decl.symbol(db);
SymTy::var(db, symbol)
}

AstTyKind::Tuple(ast_elts) => {
let mut elts: Vec<SymGenericTerm<'_>> = Vec::with_capacity(ast_elts.len());
for elt in &ast_elts {
elts.push(elt.check_in_env(env).await.into());
}
SymTy::named(
db,
crate::ir::types::SymTyName::Tuple { arity: elts.len() },
elts,
)
}
})
.await
}
Expand Down
2 changes: 1 addition & 1 deletion components/dada-ir-sym/src/ir/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ fn report_duplicate<'db>(
db,
Level::Info,
canonical_span,
format!("we will map `{id:?}` to this other definition"),
format!("we will map `{id}` to this other definition"),
)
.report(db);
}
Expand Down
3 changes: 3 additions & 0 deletions components/dada-ir-sym/src/ir/populate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ impl<'db> PopulateSignatureSymbols<'db> for AstTy<'db> {
AstTyKind::GenericDecl(ast_generic_decl) => {
ast_generic_decl.populate_signature_symbols(db, symbols)
}
AstTyKind::Tuple(elts) => elts
.iter()
.for_each(|e| e.populate_signature_symbols(db, symbols)),
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions components/dada-parser/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,15 @@ fn base_expr_precedence<'db, const SELECT: u32>(
return Ok(Some(AstExprKind::Literal(literal)));
}

if let Some(elts) = AstExpr::opt_parse_delimited(
db,
parser,
crate::tokenizer::Delimiter::Parentheses,
AstExpr::eat_comma,
)? {
return Ok(Some(AstExprKind::Tuple(elts)));
}

if let Ok(if_span) = parser.eat_keyword(Keyword::If) {
return Ok(Some(if_chain(db, parser, if_span)?));
}
Expand Down
5 changes: 4 additions & 1 deletion components/dada-parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,7 @@ trait Parse<'db>: Sized {
let input_offset = text_span.start + 1; // account for the opening delimiter
let tokenized = tokenize(db, text_span.anchor, input_offset, text);
let mut parser1 = Parser::new(db, text_span.anchor, &tokenized);
parser1.last_span = parser.last_span();
let opt_list_err = eat_method(db, &mut parser1);
parser.take_diagnostics(parser1);
Ok(Some(opt_list_err?))
Expand All @@ -557,6 +558,8 @@ trait Parse<'db>: Sized {
db: &'db dyn crate::Db,
parser: &mut Parser<'_, 'db>,
) -> Result<Option<SpanVec<'db, Self::Output>>, ParseFail<'db>> {
let start_span = parser.peek_span();

match Self::opt_parse(db, parser) {
Ok(Some(item)) => {
let mut values = vec![item];
Expand All @@ -573,7 +576,7 @@ trait Parse<'db>: Sized {
}

Ok(Some(SpanVec {
span: parser.last_span(),
span: start_span.to(db, parser.last_span()),
values,
}))
}
Expand Down
23 changes: 20 additions & 3 deletions components/dada-parser/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@ enum TyOrPerm<'db> {
/// Perm that starts with a keyword, like `my`
PermKeyword(AstPerm<'db>),

/// P1 P2
/// `P1 P2`
Apply(AstPerm<'db>, AstTy<'db>),

/// `(A, B, C)`
Tuple(SpanVec<'db, AstTy<'db>>),
}

impl<'db> Parse<'db> for TyOrPerm<'db> {
Expand Down Expand Up @@ -56,6 +59,14 @@ impl<'db> Parse<'db> for TyOrPerm<'db> {
return TyOrPerm::PermKeyword(p).maybe_apply(db, parser);
}

let start_span = parser.peek_span();
if let Some(mut elts) =
AstTy::opt_parse_delimited(db, parser, Delimiter::Parentheses, AstTy::eat_comma)?
{
elts.span = start_span.to(db, parser.last_span());
return Ok(Some(TyOrPerm::Tuple(elts)));
}

Ok(None)
}

Expand All @@ -74,6 +85,7 @@ impl<'db> Spanned<'db> for TyOrPerm<'db> {
TyOrPerm::Generic(decl) => decl.span(db),
TyOrPerm::PermKeyword(p) => p.span(db),
TyOrPerm::Apply(p, ty) => p.span(db).to(db, ty.span(db)),
TyOrPerm::Tuple(elts) => elts.span,
}
}
}
Expand Down Expand Up @@ -103,6 +115,7 @@ impl<'db> TyOrPerm<'db> {
TyOrPerm::Generic(decl) => matches!(decl.kind(db), AstGenericKind::Perm(_)),
TyOrPerm::PermKeyword(_) => true,
TyOrPerm::Apply(_, _) => false,
TyOrPerm::Tuple(_) => false,
}
}

Expand All @@ -123,16 +136,18 @@ impl<'db> TyOrPerm<'db> {
},
TyOrPerm::PermKeyword(p) => Some(p),
TyOrPerm::Apply(_, _) => None,
TyOrPerm::Tuple(_) => None,
}
}

/// True if this could syntactically be a permission.
/// True if this could syntactically be a type.
fn can_be_ty(&self, db: &'db dyn crate::Db) -> bool {
match self {
TyOrPerm::Path(..) => true,
TyOrPerm::Generic(decl) => matches!(decl.kind(db), AstGenericKind::Type(_)),
TyOrPerm::PermKeyword(_) => false,
TyOrPerm::Apply(_, _) => true,
TyOrPerm::Tuple(_) => true,
}
}

Expand All @@ -146,6 +161,7 @@ impl<'db> TyOrPerm<'db> {
},
TyOrPerm::PermKeyword(_) => None,
TyOrPerm::Apply(p, t) => Some(AstTy::new(db, span, AstTyKind::Perm(p, t))),
TyOrPerm::Tuple(elts) => Some(AstTy::new(db, span, AstTyKind::Tuple(elts))),
}
}
}
Expand Down Expand Up @@ -272,7 +288,8 @@ impl<'db> Parse<'db> for AstGenericTerm<'db> {
TyOrPerm::Generic(_)
| TyOrPerm::PermKeyword(_)
| TyOrPerm::Path(..)
| TyOrPerm::Apply(_, _) => {
| TyOrPerm::Apply(_, _)
| TyOrPerm::Tuple(_) => {
let can_be_perm = ty_or_perm.can_be_perm(db);
let can_be_ty = ty_or_perm.can_be_ty(db);

Expand Down
8 changes: 8 additions & 0 deletions tests/parser/tuple.dada
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#:fn_asts

fn main() {
let empty: () = ()
let single: (i32) = (42)
let single: (i32,) = (42,)
let nested: ((i32, i32), i32) = ((1, 2), 3)
}
Loading