Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -496,8 +496,8 @@ fn reexports_still_type_check() {
"Bool",
"Int",
Span {
lo: 128,
hi: 140,
lo: 137,
hi: 139,
},
),
),
Expand Down
18 changes: 9 additions & 9 deletions source/compiler/qsc_frontend/src/typeck/infer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,9 +308,9 @@ impl TySource {
#[derive(Clone, Debug)]
pub(super) enum ArgTy {
/// A missing argument, indicating partial application.
Hole(Ty),
Hole(Ty, Span),
/// A given argument.
Given(Ty),
Given(Ty, Span),
/// A list of arguments. This corresponds literally to tuple syntax, not to any expression of a tuple type.
Tuple(Vec<ArgTy>),
}
Expand All @@ -319,8 +319,8 @@ impl ArgTy {
/// Applies a function `f` to each type in the argument type.
fn map(self, f: &mut impl FnMut(Ty) -> Ty) -> Self {
match self {
Self::Hole(ty) => Self::Hole(f(ty)),
Self::Given(ty) => Self::Given(f(ty)),
Self::Hole(ty, span) => Self::Hole(f(ty), span),
Self::Given(ty, span) => Self::Given(f(ty), span),
Self::Tuple(items) => Self::Tuple(items.into_iter().map(|i| i.map(f)).collect()),
}
}
Expand All @@ -333,25 +333,25 @@ impl ArgTy {
// However, we do know that the type of Arg must be Eq to the type of Param, so we
// add that to the constraints.
// Preserve the hole.
(Self::Hole(arg), _) => App {
(Self::Hole(arg, arg_span), _) => App {
holes: vec![param.clone()],
constraints: vec![Constraint::Eq {
expected: param.clone(),
actual: arg.clone(),
span,
span: *arg_span,
}],
errors: Vec::new(),
},
// If `arg` is a hole, then it doesn't matter what the param is,
// because the hole can be anything.
// However, we do know that the type of Arg must be Eq to the type of Param, so we
// add that to the constraints.
(Self::Given(arg), _) => App {
(Self::Given(arg, arg_span), _) => App {
holes: Vec::new(),
constraints: vec![Constraint::Eq {
expected: param.clone(),
actual: arg.clone(),
span,
span: *arg_span,
}],
errors: Vec::new(),
},
Expand Down Expand Up @@ -410,7 +410,7 @@ impl ArgTy {

pub(super) fn to_ty(&self) -> Ty {
match self {
ArgTy::Hole(ty) | ArgTy::Given(ty) => ty.clone(),
ArgTy::Hole(ty, _) | ArgTy::Given(ty, _) => ty.clone(),
ArgTy::Tuple(items) => Ty::Tuple(items.iter().map(Self::to_ty).collect()),
}
}
Expand Down
57 changes: 42 additions & 15 deletions source/compiler/qsc_frontend/src/typeck/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,23 +266,42 @@ impl<'a> Context<'a> {
ExprKind::Block(block) => self.infer_block(block),
ExprKind::Call(callee, input) => {
let callee = self.infer_expr(callee);
let input = if has_holes(input) {
self.infer_hole_tuple_arg(input)
let input_expr = &**input;
let input = if has_holes(input_expr) {
self.infer_hole_tuple_arg(input_expr)
} else {
let ty = self.infer_expr(input);
let ty = self.infer_expr(input_expr);
// If the outermost element is a tuple, we must wrap it in an `ArgTy::Tuple`.
match ty {
if let Partial {
ty: Ty::Tuple(tys),
diverges,
} = ty
{
let spans: Vec<_> = if let ExprKind::Tuple(items) = input_expr.kind.as_ref()
{
items.iter().map(|item| item.span).collect()
} else {
vec![input_expr.span; tys.len()]
};
Partial {
ty: Ty::Tuple(tys),
ty: ArgTy::Tuple(
tys.into_iter()
.zip(spans)
.map(|(ty, span)| ArgTy::Given(ty, span))
.collect(),
),
diverges,
} => Partial {
ty: ArgTy::Tuple(tys.into_iter().map(ArgTy::Given).collect()),
diverges,
},
_ => Partial {
ty: ArgTy::Given(ty.ty),
}
} else {
let arg_span = if let ExprKind::Paren(inner) = input_expr.kind.as_ref() {
inner.span
} else {
input_expr.span
};
Partial {
ty: ArgTy::Given(ty.ty, arg_span),
diverges: false,
},
}
}
};
let output_ty = if callee.ty == Ty::Err {
Expand Down Expand Up @@ -723,7 +742,7 @@ impl<'a> Context<'a> {
ExprKind::Hole => {
let ty = self.inferrer.fresh_ty(TySource::not_divergent(expr.span));
self.record(expr.id, ty.clone());
converge(ArgTy::Hole(ty))
converge(ArgTy::Hole(ty, expr.span))
}
ExprKind::Paren(inner) => {
let inner = self.infer_hole_tuple_arg(inner);
Expand All @@ -739,9 +758,17 @@ impl<'a> Context<'a> {
tys.push(item.ty);
}
self.record(expr.id, Ty::Tuple(tys.iter().map(ArgTy::to_ty).collect()));
self.diverge_if_map(ArgTy::Given, diverges, converge(ArgTy::Tuple(tys)))
let span = expr.span;
self.diverge_if_map(
|ty| ArgTy::Given(ty, span),
diverges,
converge(ArgTy::Tuple(tys)),
)
}
_ => {
let span = expr.span;
self.infer_expr(expr).map(|ty| ArgTy::Given(ty, span))
}
_ => self.infer_expr(expr).map(ArgTy::Given),
}
}

Expand Down
64 changes: 45 additions & 19 deletions source/compiler/qsc_frontend/src/typeck/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -476,15 +476,15 @@ fn int_as_double_error() {
}
"},
"Microsoft.Quantum.Convert.IntAsDouble(false)",
&expect![[r#"
&expect![[r##"
#8 62-71 "(a : Int)" : ?
#9 63-70 "a : Int" : ?
#18 103-147 "Microsoft.Quantum.Convert.IntAsDouble(false)" : Double
#19 103-140 "Microsoft.Quantum.Convert.IntAsDouble" : (Int -> Double)
#25 140-147 "(false)" : Bool
#26 141-146 "false" : Bool
Error(Type(Error(TyMismatch("Int", "Bool", Span { lo: 103, hi: 147 }))))
"#]],
Error(Type(Error(TyMismatch("Int", "Bool", Span { lo: 141, hi: 146 }))))
"##]],
);
}

Expand Down Expand Up @@ -538,7 +538,7 @@ fn single_arg_for_tuple() {
#31 124-126 "Ry" : ((Double, Qubit) => Unit is Adj + Ctl)
#34 126-129 "(q)" : Qubit
#35 127-128 "q" : Qubit
Error(Type(Error(TyMismatch("(Double, Qubit)", "Qubit", Span { lo: 124, hi: 129 }))))
Error(Type(Error(TyMismatch("(Double, Qubit)", "Qubit", Span { lo: 127, hi: 128 }))))
"##]],
);
}
Expand Down Expand Up @@ -1732,7 +1732,7 @@ fn call_controlled_error() {
Controlled A.Foo([1], q);
}
"},
&expect![[r#"
&expect![[r##"
#6 31-42 "(q : Qubit)" : Qubit
#7 32-41 "q : Qubit" : Qubit
#17 72-75 "..." : Qubit
Expand All @@ -1752,8 +1752,8 @@ fn call_controlled_error() {
#39 163-166 "[1]" : Int[]
#40 164-165 "1" : Int
#41 168-169 "q" : Qubit
Error(Type(Error(TyMismatch("Qubit", "Int", Span { lo: 146, hi: 170 }))))
"#]],
Error(Type(Error(TyMismatch("Qubit", "Int", Span { lo: 163, hi: 166 }))))
"##]],
);
}

Expand All @@ -1775,6 +1775,32 @@ fn adj_requires_unit_return() {
);
}

#[test]
fn should_have_been_array() {
check(
indoc! {"
namespace A {
operation Foo(qs: Qubit[]) : Unit is Adj {
Foo(qs[0])
}
}
"},
"",
&expect![[r##"
#6 31-44 "(qs: Qubit[])" : Qubit[]
#7 32-43 "qs: Qubit[]" : Qubit[]
#17 59-85 "{\n Foo(qs[0])\n }" : Unit
#19 69-79 "Foo(qs[0])" : Unit
#20 69-72 "Foo" : (Qubit[] => Unit is Adj)
#23 72-79 "(qs[0])" : Qubit
#24 73-78 "qs[0]" : Qubit
#25 73-75 "qs" : Qubit[]
#28 76-77 "0" : Int
Error(Type(Error(TyMismatch("Qubit[]", "Qubit", Span { lo: 73, hi: 78 }))))
"##]],
);
}

#[test]
fn ctl_requires_unit_return() {
check(
Expand Down Expand Up @@ -1979,7 +2005,7 @@ fn fail_in_call_args_checks_non_divergent_types() {
#34 67-78 "fail \"true\"" : Int
#35 72-78 "\"true\"" : String
#36 80-83 "3.0" : Double
Error(Type(Error(TyMismatch("Int", "Double", Span { lo: 60, hi: 84 }))))
Error(Type(Error(TyMismatch("Int", "Double", Span { lo: 80, hi: 83 }))))
"##]],
);
}
Expand Down Expand Up @@ -2175,7 +2201,7 @@ fn return_in_call_args_checks_non_divergent_types() {
#34 67-80 "return \"true\"" : Int
#35 74-80 "\"true\"" : String
#36 82-85 "3.0" : Double
Error(Type(Error(TyMismatch("Int", "Double", Span { lo: 60, hi: 86 }))))
Error(Type(Error(TyMismatch("Int", "Double", Span { lo: 82, hi: 85 }))))
"##]],
);
}
Expand Down Expand Up @@ -2767,7 +2793,7 @@ fn newtype_cons_wrong_input() {
#19 70-76 "NewInt" : (Int -> UDT<"NewInt": Item 1 (Package 2)>)
#22 76-81 "(5.0)" : Double
#23 77-80 "5.0" : Double
Error(Type(Error(TyMismatch("Int", "Double", Span { lo: 70, hi: 81 }))))
Error(Type(Error(TyMismatch("Int", "Double", Span { lo: 77, hi: 80 }))))
"##]],
);
}
Expand Down Expand Up @@ -4134,7 +4160,7 @@ fn functors_in_arg_subset_of_ctl_adj() {
operation Bar(q : Qubit) : () is Adj {}
Foo(Bar);
}",
&expect![[r#"
&expect![[r##"
#1 0-150 "{\n operation Foo(op : Qubit => () is Adj + Ctl) : () {}\n operation Bar(q : Qubit) : () is Adj {}\n Foo(Bar);\n }" : Unit
#2 0-150 "{\n operation Foo(op : Qubit => () is Adj + Ctl) : () {}\n operation Bar(q : Qubit) : () is Adj {}\n Foo(Bar);\n }" : Unit
#7 27-58 "(op : Qubit => () is Adj + Ctl)" : (Qubit => Unit is Adj + Ctl)
Expand All @@ -4147,8 +4173,8 @@ fn functors_in_arg_subset_of_ctl_adj() {
#35 131-134 "Foo" : ((Qubit => Unit is Adj) => Unit)
#38 134-139 "(Bar)" : (Qubit => Unit is Adj)
#39 135-138 "Bar" : (Qubit => Unit is Adj)
Error(Type(Error(MissingFunctor(Value(CtlAdj), Value(Adj), Span { lo: 131, hi: 139 }))))
"#]],
Error(Type(Error(MissingFunctor(Value(CtlAdj), Value(Adj), Span { lo: 135, hi: 138 }))))
"##]],
);
}

Expand Down Expand Up @@ -4187,7 +4213,7 @@ fn functors_in_arg_nested_arrow_superset_of_adj() {
operation Bar(op : Qubit => () is Adj + Ctl) : () {}
Foo(Bar);
}",
&expect![[r#"
&expect![[r##"
#1 0-165 "{\n operation Foo(op : (Qubit => () is Adj) => ()) : () {}\n operation Bar(op : Qubit => () is Adj + Ctl) : () {}\n Foo(Bar);\n }" : Unit
#2 0-165 "{\n operation Foo(op : (Qubit => () is Adj) => ()) : () {}\n operation Bar(op : Qubit => () is Adj + Ctl) : () {}\n Foo(Bar);\n }" : Unit
#7 27-60 "(op : (Qubit => () is Adj) => ())" : ((Qubit => Unit is Adj) => Unit)
Expand All @@ -4200,8 +4226,8 @@ fn functors_in_arg_nested_arrow_superset_of_adj() {
#40 146-149 "Foo" : (((Qubit => Unit is Adj) => Unit) => Unit)
#43 149-154 "(Bar)" : ((Qubit => Unit is Adj) => Unit)
#44 150-153 "Bar" : ((Qubit => Unit is Adj) => Unit)
Error(Type(Error(MissingFunctor(Value(CtlAdj), Value(Adj), Span { lo: 146, hi: 154 }))))
"#]],
Error(Type(Error(MissingFunctor(Value(CtlAdj), Value(Adj), Span { lo: 150, hi: 153 }))))
"##]],
);
}

Expand Down Expand Up @@ -4293,7 +4319,7 @@ fn functors_in_arg_array_subset_of_adj() {
operation Bar(q : Qubit) : () {}
Foo([Bar]);
}",
&expect![[r#"
&expect![[r##"
#1 0-144 "{\n operation Foo(ops : (Qubit => () is Adj)[]) : () {}\n operation Bar(q : Qubit) : () {}\n Foo([Bar]);\n }" : Unit
#2 0-144 "{\n operation Foo(ops : (Qubit => () is Adj)[]) : () {}\n operation Bar(q : Qubit) : () {}\n Foo([Bar]);\n }" : Unit
#7 27-57 "(ops : (Qubit => () is Adj)[])" : (Qubit => Unit is Adj)[]
Expand All @@ -4307,8 +4333,8 @@ fn functors_in_arg_array_subset_of_adj() {
#37 126-133 "([Bar])" : (Qubit => Unit)[]
#38 127-132 "[Bar]" : (Qubit => Unit)[]
#39 128-131 "Bar" : (Qubit => Unit)
Error(Type(Error(MissingFunctor(Value(Adj), Value(Empty), Span { lo: 123, hi: 133 }))))
"#]],
Error(Type(Error(MissingFunctor(Value(Adj), Value(Empty), Span { lo: 127, hi: 132 }))))
"##]],
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -380,8 +380,8 @@ fn transitive_class_check_fail() {
#80 516-519 "Foo" : (BigInt -> BigInt)
#83 519-524 "(10L)" : BigInt
#84 520-523 "10L" : BigInt
Error(Type(Error(MissingClassInteger("'F", Span { lo: 259, hi: 265 }))))
Error(Type(Error(MissingClassInteger("Double", Span { lo: 474, hi: 482 }))))
Error(Type(Error(MissingClassInteger("'F", Span { lo: 263, hi: 264 }))))
Error(Type(Error(MissingClassInteger("Double", Span { lo: 478, hi: 481 }))))
"##]],
);
}
Expand Down Expand Up @@ -606,8 +606,8 @@ fn integral_fail() {
#45 210-213 "Foo" : (Bool -> Bool)
#48 213-219 "(true)" : Bool
#49 214-218 "true" : Bool
Error(Type(Error(MissingClassInteger("Double", Span { lo: 176, hi: 184 }))))
Error(Type(Error(MissingClassInteger("Bool", Span { lo: 210, hi: 219 }))))
Error(Type(Error(MissingClassInteger("Double", Span { lo: 180, hi: 183 }))))
Error(Type(Error(MissingClassInteger("Bool", Span { lo: 214, hi: 218 }))))
"##]],
);
}
Expand Down Expand Up @@ -736,8 +736,8 @@ fn show_and_eq_should_fail() {
#69 344-352 "(1, \"2\")" : (Int, String)
#70 345-346 "1" : Int
#71 348-351 "\"2\"" : String
Error(Type(Error(TyMismatch("Int", "Bool", Span { lo: 303, hi: 315 }))))
Error(Type(Error(TyMismatch("Int", "String", Span { lo: 341, hi: 352 }))))
Error(Type(Error(TyMismatch("Int", "Bool", Span { lo: 310, hi: 314 }))))
Error(Type(Error(TyMismatch("Int", "String", Span { lo: 348, hi: 351 }))))
"##]],
);
}
Expand Down
Loading