From 0ac93cd579ca394b66589cf176dc93406dc4aeb2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 27 Nov 2024 20:15:06 +0000 Subject: [PATCH 1/2] Structurally resolve before adjust_for_branches --- compiler/rustc_hir_typeck/src/_match.rs | 2 +- compiler/rustc_hir_typeck/src/expectation.rs | 8 ++++++-- compiler/rustc_hir_typeck/src/expr.rs | 2 +- .../typeck/structurally-resolve-in-resolve_for_branch.rs | 8 ++++++++ 4 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 tests/ui/traits/next-solver/typeck/structurally-resolve-in-resolve_for_branch.rs diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index bfdf764d299b4..7e3cb7914a9f7 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -57,7 +57,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // type in that case) let mut all_arms_diverge = Diverges::WarnedAlways; - let expected = orig_expected.adjust_for_branches(self); + let expected = orig_expected.adjust_for_branches(self, expr.span); debug!(?expected); let mut coercion = { diff --git a/compiler/rustc_hir_typeck/src/expectation.rs b/compiler/rustc_hir_typeck/src/expectation.rs index 4653458b5ddcc..93fa6f863d17f 100644 --- a/compiler/rustc_hir_typeck/src/expectation.rs +++ b/compiler/rustc_hir_typeck/src/expectation.rs @@ -39,10 +39,14 @@ impl<'a, 'tcx> Expectation<'tcx> { // an expected type. Otherwise, we might write parts of the type // when checking the 'then' block which are incompatible with the // 'else' branch. - pub(super) fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> { + pub(super) fn adjust_for_branches( + &self, + fcx: &FnCtxt<'a, 'tcx>, + span: Span, + ) -> Expectation<'tcx> { match *self { ExpectHasType(ety) => { - let ety = fcx.shallow_resolve(ety); + let ety = fcx.try_structurally_resolve_type(span, ety); if !ety.is_ty_var() { ExpectHasType(ety) } else { NoExpectation } } ExpectRvalueLikeUnsized(ety) => ExpectRvalueLikeUnsized(ety), diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 1610848958e59..dd1650e0634aa 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1290,7 +1290,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let cond_diverges = self.diverges.get(); self.diverges.set(Diverges::Maybe); - let expected = orig_expected.adjust_for_branches(self); + let expected = orig_expected.adjust_for_branches(self, sp); let then_ty = self.check_expr_with_expectation(then_expr, expected); let then_diverges = self.diverges.get(); self.diverges.set(Diverges::Maybe); diff --git a/tests/ui/traits/next-solver/typeck/structurally-resolve-in-resolve_for_branch.rs b/tests/ui/traits/next-solver/typeck/structurally-resolve-in-resolve_for_branch.rs new file mode 100644 index 0000000000000..d406f3949a28a --- /dev/null +++ b/tests/ui/traits/next-solver/typeck/structurally-resolve-in-resolve_for_branch.rs @@ -0,0 +1,8 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +pub fn repro() -> impl FnMut() { + if true { || () } else { || () } +} + +fn main() {} From 0cf93703a51f29660572cd680ab09b44255b37b4 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 4 Dec 2024 20:37:00 +0000 Subject: [PATCH 2/2] Resolve more --- compiler/rustc_hir_typeck/src/_match.rs | 3 ++- compiler/rustc_hir_typeck/src/expectation.rs | 2 +- compiler/rustc_hir_typeck/src/expr.rs | 10 +++---- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 15 +++++------ .../auto-trait-selection-freeze.next.stderr | 21 +++------------ .../auto-trait-selection.next.stderr | 21 +++------------ .../typeck/resolve-expectations.rs | 26 +++++++++++++++++++ 7 files changed, 49 insertions(+), 49 deletions(-) create mode 100644 tests/ui/traits/next-solver/typeck/resolve-expectations.rs diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 7e3cb7914a9f7..243313ee8767a 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -57,7 +57,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // type in that case) let mut all_arms_diverge = Diverges::WarnedAlways; - let expected = orig_expected.adjust_for_branches(self, expr.span); + let expected = + orig_expected.try_structurally_resolve_and_adjust_for_branches(self, expr.span); debug!(?expected); let mut coercion = { diff --git a/compiler/rustc_hir_typeck/src/expectation.rs b/compiler/rustc_hir_typeck/src/expectation.rs index 93fa6f863d17f..6d95b6917e296 100644 --- a/compiler/rustc_hir_typeck/src/expectation.rs +++ b/compiler/rustc_hir_typeck/src/expectation.rs @@ -39,7 +39,7 @@ impl<'a, 'tcx> Expectation<'tcx> { // an expected type. Otherwise, we might write parts of the type // when checking the 'then' block which are incompatible with the // 'else' branch. - pub(super) fn adjust_for_branches( + pub(super) fn try_structurally_resolve_and_adjust_for_branches( &self, fcx: &FnCtxt<'a, 'tcx>, span: Span, diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index dd1650e0634aa..18d3c4628f502 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -625,7 +625,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| { - match ty.kind() { + match self.try_structurally_resolve_type(expr.span, ty).kind() { ty::Ref(_, ty, _) | ty::RawPtr(ty, _) => { if oprnd.is_syntactic_place_expr() { // Places may legitimately have unsized types. @@ -1290,7 +1290,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let cond_diverges = self.diverges.get(); self.diverges.set(Diverges::Maybe); - let expected = orig_expected.adjust_for_branches(self, sp); + let expected = orig_expected.try_structurally_resolve_and_adjust_for_branches(self, sp); let then_ty = self.check_expr_with_expectation(then_expr, expected); let then_diverges = self.diverges.get(); self.diverges.set(Diverges::Maybe); @@ -1351,8 +1351,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rhs: &'tcx hir::Expr<'tcx>, span: Span, ) -> Ty<'tcx> { - let expected_ty = expected.coercion_target_type(self, expr.span); - if expected_ty == self.tcx.types.bool { + let expected_ty = expected.only_has_type(self); + if expected_ty == Some(self.tcx.types.bool) { let guar = self.expr_assign_expected_bool_error(expr, lhs, rhs, span); return Ty::new_error(self.tcx, guar); } @@ -1636,7 +1636,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let element_ty = if !args.is_empty() { let coerce_to = expected .to_option(self) - .and_then(|uty| match *uty.kind() { + .and_then(|uty| match *self.try_structurally_resolve_type(expr.span, uty).kind() { ty::Array(ty, _) | ty::Slice(ty) => Some(ty), _ => None, }) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 9c18dbd422d90..4c9674aba85b9 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -939,18 +939,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // can be collated pretty easily if needed. // Next special case: if there is only one "Incompatible" error, just emit that - if let [ + if let &[ Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(err))), ] = &errors[..] { - let (formal_ty, expected_ty) = formal_and_expected_inputs[*expected_idx]; - let (provided_ty, provided_arg_span) = provided_arg_tys[*provided_idx]; + let (formal_ty, expected_ty) = formal_and_expected_inputs[expected_idx]; + let (provided_ty, provided_arg_span) = provided_arg_tys[provided_idx]; let trace = mk_trace(provided_arg_span, (formal_ty, expected_ty), provided_ty); - let mut err = - self.err_ctxt().report_and_explain_type_error(trace, self.param_env, *err); + let mut err = self.err_ctxt().report_and_explain_type_error(trace, self.param_env, err); self.emit_coerce_suggestions( &mut err, - provided_args[*provided_idx], + provided_args[provided_idx], provided_ty, Expectation::rvalue_hint(self, expected_ty) .only_has_type(self) @@ -985,7 +984,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.suggest_ptr_null_mut( expected_ty, provided_ty, - provided_args[*provided_idx], + provided_args[provided_idx], &mut err, ); @@ -995,7 +994,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_ident, expected_ty, provided_ty, - provided_args[*provided_idx], + provided_args[provided_idx], is_method, ); diff --git a/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr b/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr index 5caf0eb2fd4e3..54ceec0aff5d7 100644 --- a/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr +++ b/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr @@ -1,22 +1,9 @@ -error[E0283]: type annotations needed - --> $DIR/auto-trait-selection-freeze.rs:19:16 +error[E0284]: type annotations needed: cannot satisfy `impl Sized == _` + --> $DIR/auto-trait-selection-freeze.rs:19:5 | LL | if false { is_trait(foo()) } else { Default::default() } - | ^^^^^^^^ ----- type must be known at this point - | | - | cannot infer type of the type parameter `T` declared on the function `is_trait` - | - = note: cannot satisfy `_: Trait<_>` -note: required by a bound in `is_trait` - --> $DIR/auto-trait-selection-freeze.rs:11:16 - | -LL | fn is_trait, U: Default>(_: T) -> U { - | ^^^^^^^^ required by this bound in `is_trait` -help: consider specifying the generic arguments - | -LL | if false { is_trait::(foo()) } else { Default::default() } - | ++++++++ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `impl Sized == _` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0283`. +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/impl-trait/auto-trait-selection.next.stderr b/tests/ui/impl-trait/auto-trait-selection.next.stderr index d34fdcc44967f..7acb9fd41b730 100644 --- a/tests/ui/impl-trait/auto-trait-selection.next.stderr +++ b/tests/ui/impl-trait/auto-trait-selection.next.stderr @@ -1,22 +1,9 @@ -error[E0283]: type annotations needed - --> $DIR/auto-trait-selection.rs:15:16 +error[E0284]: type annotations needed: cannot satisfy `impl Sized == _` + --> $DIR/auto-trait-selection.rs:15:5 | LL | if false { is_trait(foo()) } else { Default::default() } - | ^^^^^^^^ ----- type must be known at this point - | | - | cannot infer type of the type parameter `T` declared on the function `is_trait` - | - = note: cannot satisfy `_: Trait<_>` -note: required by a bound in `is_trait` - --> $DIR/auto-trait-selection.rs:7:16 - | -LL | fn is_trait, U: Default>(_: T) -> U { - | ^^^^^^^^ required by this bound in `is_trait` -help: consider specifying the generic arguments - | -LL | if false { is_trait::(foo()) } else { Default::default() } - | ++++++++ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `impl Sized == _` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0283`. +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/traits/next-solver/typeck/resolve-expectations.rs b/tests/ui/traits/next-solver/typeck/resolve-expectations.rs new file mode 100644 index 0000000000000..d6b3816b9eb12 --- /dev/null +++ b/tests/ui/traits/next-solver/typeck/resolve-expectations.rs @@ -0,0 +1,26 @@ +//@ check-pass +//@ compile-flags: -Znext-solver + +trait Mirror { + type Assoc; +} +impl Mirror for T { + type Assoc = T; +} + +fn id(t: T) -> T { t } + +trait Foo {} +impl Foo for i32 {} +impl Foo for u32 {} + +fn main() { + // Make sure we resolve expected pointee of addr-of. + id::<<&&dyn Foo as Mirror>::Assoc>(&id(&1)); + + // Make sure we resolve expected element of array. + id::<<[Box; 2] as Mirror>::Assoc>([Box::new(1i32), Box::new(1u32)]); + + // Make sure we resolve expected element of tuple. + id::<<(Box,) as Mirror>::Assoc>((Box::new(1i32),)); +}