Skip to content

Commit 9a96759

Browse files
committed
Lower tuples correctly, clean up parsing
1 parent ed392f4 commit 9a96759

File tree

4 files changed

+96
-23
lines changed

4 files changed

+96
-23
lines changed

chalk-integration/src/lowering.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,14 +1074,18 @@ impl LowerTy for Ty {
10741074
};
10751075
Ok(chalk_ir::TyData::Function(function).intern(interner))
10761076
}
1077-
Ty::Tuple { arity } => Ok(chalk_ir::TyData::Apply(chalk_ir::ApplicationTy {
1078-
name: chalk_ir::TypeName::Tuple(arity),
1079-
substitution: chalk_ir::Substitution::empty(interner),
1077+
Ty::Tuple { ref types } => Ok(chalk_ir::TyData::Apply(chalk_ir::ApplicationTy {
1078+
name: chalk_ir::TypeName::Tuple(types.len()),
1079+
substitution: chalk_ir::Substitution::from_fallible(
1080+
interner,
1081+
types.iter().map(|t| Ok(t.lower(env)?)),
1082+
)?,
10801083
})
10811084
.intern(interner)),
10821085

10831086
Ty::Scalar { ty } => Ok(chalk_ir::TyData::Apply(chalk_ir::ApplicationTy {
10841087
name: chalk_ir::TypeName::Scalar(ast_scalar_to_chalk_scalar(ty)),
1088+
// substitution: chalk_ir::Substitution::from_fallible(interner, ty.lower(env)?)?,
10851089
substitution: chalk_ir::Substitution::empty(interner),
10861090
})
10871091
.intern(interner)),

chalk-parse/src/ast.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ pub enum Ty {
176176
ty: Box<Ty>,
177177
},
178178
Tuple {
179-
arity: usize,
179+
types: Vec<Box<Ty>>,
180180
},
181181
Scalar {
182182
ty: ScalarType,

chalk-parse/src/parser.lalrpop

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -212,10 +212,14 @@ ScalarType: ScalarType = {
212212
};
213213

214214
TupleOrParensInner: Ty = {
215-
<l:Comma2<Ty>> => Ty::Tuple { arity: l.len() },
216-
<Ty> "," => Ty::Tuple { arity: 1 },
217215
<Ty>,
218-
() => Ty::Tuple { arity: 0 },
216+
<first:Ty> "," <rest:Comma<Ty>> => {
217+
let mut types = Vec::with_capacity(rest.len() + 1);
218+
types.push(Box::new(first));
219+
types.extend(rest.into_iter().map(Box::new));
220+
Ty::Tuple { types }
221+
},
222+
() => Ty::Tuple { types: vec![] },
219223
};
220224

221225
Lifetime: Lifetime = {
@@ -370,26 +374,11 @@ Separator1<S, T>: Vec<T> = {
370374
}
371375
};
372376

373-
Separator2<S, T>: Vec<T> = {
374-
<t1:T> S <t2:T> => vec![t1, t2],
375-
<t1:T> S <t2:T> S <v:Separator<S, T>> => {
376-
let mut v = v;
377-
v.push(t1);
378-
v.push(t2);
379-
v
380-
}
381-
};
382-
383377
#[inline]
384378
Comma<T>: Vec<T> = {
385379
<Separator<",", T>>
386380
};
387381

388-
#[inline]
389-
Comma2<T>: Vec<T> = {
390-
<Separator2<",", T>>
391-
};
392-
393382
#[inline]
394383
SemiColon<T>: Vec<T> = {
395384
<Separator<";", T>>

tests/lowering/mod.rs

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,9 +470,89 @@ fn scalars() {
470470
struct i32 { }
471471
}
472472

473-
// TODO: improve this error message
474473
error_msg {
475474
"parse error: UnrecognizedToken { token: (8, Token(45, \"i32\"), 11), expected: [\"r#\\\"([A-Za-z]|_)([A-Za-z0-9]|_)*\\\"#\"] }"
476475
}
477476
}
478477
}
478+
479+
#[test]
480+
fn tuple_trait_impl() {
481+
let db = ChalkDatabase::with(
482+
"
483+
trait Foo { }
484+
struct S1 { }
485+
impl Foo for (S1, S1) { }
486+
",
487+
SolverChoice::default(),
488+
);
489+
let goal = db.parse_and_lower_goal("(S1, S1): Foo").unwrap();
490+
db.with_program(|_| {
491+
assert_eq!(format!("{:?}", goal), "Implemented(2<S1, S1>: Foo)");
492+
});
493+
let db = ChalkDatabase::with(
494+
"
495+
trait Foo { }
496+
impl Foo for (i32, i32, (i32,)) { }
497+
",
498+
SolverChoice::default(),
499+
);
500+
let goal = db.parse_and_lower_goal("(i32, i32, (i32,)): Foo").unwrap();
501+
db.with_program(|_| {
502+
assert_eq!(
503+
format!("{:?}", goal),
504+
"Implemented(3<Int(I32), Int(I32), 1<Int(I32)>>: Foo)"
505+
);
506+
});
507+
}
508+
509+
#[test]
510+
fn scalar_trait_impl() {
511+
let db = ChalkDatabase::with(
512+
"
513+
trait Foo { }
514+
impl Foo for usize { }
515+
impl Foo for isize { }
516+
impl<T1, T2> Foo for (T1, T2) where T1: Foo, T2: Foo { }
517+
impl<T> Foo for (T,T,T) where T: Foo { }
518+
",
519+
SolverChoice::default(),
520+
);
521+
let goal = db.parse_and_lower_goal("(usize, usize): Foo").unwrap();
522+
db.with_program(|_| {
523+
assert_eq!(
524+
format!("{:?}", goal),
525+
"Implemented(2<Uint(Usize), Uint(Usize)>: Foo)"
526+
);
527+
});
528+
let goal = db.parse_and_lower_goal("(usize, isize): Foo").unwrap();
529+
db.with_program(|_| {
530+
assert_eq!(
531+
format!("{:?}", goal),
532+
"Implemented(2<Uint(Usize), Int(Isize)>: Foo)"
533+
);
534+
});
535+
let goal = db.parse_and_lower_goal("(usize, bool): Foo").unwrap();
536+
db.with_program(|_| {
537+
// TODO: This should fail (Foo is not implemented for bool)
538+
assert_eq!(
539+
format!("{:?}", goal),
540+
"Implemented(2<Uint(Usize), Bool>: Foo)"
541+
);
542+
});
543+
let goal = db.parse_and_lower_goal("(usize,usize,usize): Foo").unwrap();
544+
db.with_program(|_| {
545+
assert_eq!(
546+
format!("{:?}", goal),
547+
"Implemented(3<Uint(Usize), Uint(Usize), Uint(Usize)>: Foo)"
548+
);
549+
});
550+
let goal = db.parse_and_lower_goal("(char,u8,i8): Foo").unwrap();
551+
db.with_program(|_| {
552+
// TODO: This should fail (the three types are not the same)
553+
assert_eq!(
554+
format!("{:?}", goal),
555+
"Implemented(3<Char, Uint(U8), Int(I8)>: Foo)"
556+
);
557+
});
558+
}

0 commit comments

Comments
 (0)