Skip to content

Commit

Permalink
Fix hover type shown for lambda passed to generic function (#1161)
Browse files Browse the repository at this point in the history
This fixes the issue by adding the original functor set for any functor
params to the data structure and updates the custom display used in
hover to print the actual functors rather than the param.

Fixes #1148
  • Loading branch information
swernli authored Feb 14, 2024
1 parent a3b9d04 commit 80d5550
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 10 deletions.
2 changes: 1 addition & 1 deletion compiler/qsc_eval/src/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,7 @@ fn lower_functor_set(functors: &qsc_hir::ty::FunctorSet) -> qsc_fir::ty::Functor
qsc_hir::ty::FunctorSet::Value(v) => {
qsc_fir::ty::FunctorSet::Value(lower_functor_set_value(v))
}
qsc_hir::ty::FunctorSet::Param(p) => {
qsc_hir::ty::FunctorSet::Param(p, _) => {
qsc_fir::ty::FunctorSet::Param(ParamId::from(usize::from(p)))
}
qsc_hir::ty::FunctorSet::Infer(i) => {
Expand Down
2 changes: 1 addition & 1 deletion compiler/qsc_frontend/src/typeck/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ fn synthesize_functor_params(next_param: &mut ParamId, ty: &mut Ty) -> Vec<Gener
Ty::Arrow(arrow) => match arrow.functors {
FunctorSet::Value(functors) if arrow.kind == hir::CallableKind::Operation => {
let param = GenericParam::Functor(functors);
arrow.functors = FunctorSet::Param(*next_param);
arrow.functors = FunctorSet::Param(*next_param, functors);
*next_param = next_param.successor();
vec![param]
}
Expand Down
22 changes: 14 additions & 8 deletions compiler/qsc_hir/src/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,16 @@ impl Ty {
CallableKind::Function => "->",
CallableKind::Operation => "=>",
};
let functors = if arrow.functors == FunctorSet::Value(FunctorSetValue::Empty) {
String::new()
} else {
format!(" is {}", arrow.functors)

let functors = match arrow.functors {
FunctorSet::Value(FunctorSetValue::Empty)
| FunctorSet::Param(_, FunctorSetValue::Empty) => String::new(),
FunctorSet::Value(_) | FunctorSet::Infer(_) => {
format!(" is {}", arrow.functors)
}
FunctorSet::Param(_, functors) => {
format!(" is {functors}")
}
};
format!(
"({} {arrow_symbol} {}{functors})",
Expand Down Expand Up @@ -231,7 +237,7 @@ fn instantiate_arrow_ty<'a>(
) -> Result<Arrow, InstantiationError> {
let input = instantiate_ty(arg, &arrow.input)?;
let output = instantiate_ty(arg, &arrow.output)?;
let functors = if let FunctorSet::Param(param) = arrow.functors {
let functors = if let FunctorSet::Param(param, _) = arrow.functors {
match arg(&param) {
Some(GenericArg::Functor(functor_arg)) => *functor_arg,
Some(_) => return Err(InstantiationError::Kind(param)),
Expand Down Expand Up @@ -409,7 +415,7 @@ pub enum FunctorSet {
/// An evaluated set.
Value(FunctorSetValue),
/// A functor parameter.
Param(ParamId),
Param(ParamId, FunctorSetValue),
/// A placeholder functor variable used during type inference.
Infer(InferFunctorId),
}
Expand All @@ -424,7 +430,7 @@ impl FunctorSet {
pub fn expect_value(self, msg: &str) -> FunctorSetValue {
match self {
Self::Value(value) => value,
Self::Param(_) | Self::Infer(_) => panic!("{msg}"),
Self::Param(_, _) | Self::Infer(_) => panic!("{msg}"),
}
}
}
Expand All @@ -433,7 +439,7 @@ impl Display for FunctorSet {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Self::Value(value) => Display::fmt(value, f),
Self::Param(param) => write!(f, "Param<{param}>"),
Self::Param(param, _) => write!(f, "Param<{param}>"),
Self::Infer(infer) => Display::fmt(infer, f),
}
}
Expand Down
20 changes: 20 additions & 0 deletions language_service/src/hover/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,26 @@ fn callable_param_doc() {
);
}

#[test]
fn callable_generic_functor_display() {
check(
indoc! {"
namespace Test {
operation Foo(op : (Qubit => Unit is Adj)) : Unit {}
operation Main() : Unit {
◉Fo↘o◉;
}
}
"},
&expect![[r#"
```qsharp
Test
operation Foo(op : (Qubit => Unit is Adj)) : Unit
```
"#]],
);
}

#[test]
fn udt_field_incorrect() {
check_none(indoc! {r#"
Expand Down

0 comments on commit 80d5550

Please sign in to comment.