Skip to content

Commit 4b80bc2

Browse files
committed
Weaken the expectation to ExpectRvalueLikeUnsized for expected input tys that do not satisfy the callee bounds
1 parent 61df3da commit 4b80bc2

15 files changed

+110
-94
lines changed

compiler/rustc_hir_typeck/src/callee.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use rustc_hir::def::{self, CtorKind, Namespace, Res};
77
use rustc_hir::def_id::DefId;
88
use rustc_hir::{self as hir, HirId, LangItem};
99
use rustc_hir_analysis::autoderef::Autoderef;
10+
use rustc_hir_analysis::hir_ty_lowering::IsMethodCall;
1011
use rustc_infer::infer::BoundRegionConversionTime;
1112
use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode};
1213
use rustc_middle::ty::adjustment::{
@@ -573,6 +574,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
573574
self.check_argument_types(
574575
call_expr.span,
575576
call_expr,
577+
IsMethodCall::No,
576578
fn_sig.inputs(),
577579
fn_sig.output(),
578580
expected,
@@ -883,6 +885,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
883885
self.check_argument_types(
884886
call_expr.span,
885887
call_expr,
888+
IsMethodCall::No,
886889
fn_sig.inputs(),
887890
fn_sig.output(),
888891
expected,
@@ -962,6 +965,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
962965
self.check_argument_types(
963966
call_expr.span,
964967
call_expr,
968+
IsMethodCall::Yes,
965969
&method.sig.inputs()[1..],
966970
method.sig.output(),
967971
expected,

compiler/rustc_hir_typeck/src/expr.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use rustc_hir::def_id::DefId;
2121
use rustc_hir::lang_items::LangItem;
2222
use rustc_hir::{ExprKind, HirId, QPath, find_attr, is_range_literal};
2323
use rustc_hir_analysis::NoVariantNamed;
24-
use rustc_hir_analysis::hir_ty_lowering::{FeedConstTy, HirTyLowerer as _};
24+
use rustc_hir_analysis::hir_ty_lowering::{FeedConstTy, HirTyLowerer as _, IsMethodCall};
2525
use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk, RegionVariableOrigin};
2626
use rustc_infer::traits::query::NoSolution;
2727
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
@@ -1494,6 +1494,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14941494
self.check_argument_types(
14951495
segment.ident.span,
14961496
expr,
1497+
IsMethodCall::Yes,
14971498
&method.sig.inputs()[1..],
14981499
method.sig.output(),
14991500
expected,
@@ -1516,6 +1517,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15161517
self.check_argument_types(
15171518
segment.ident.span,
15181519
expr,
1520+
IsMethodCall::Yes,
15191521
&err_inputs,
15201522
err_output,
15211523
NoExpectation,

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

Lines changed: 88 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use rustc_hir::def_id::DefId;
1010
use rustc_hir::intravisit::Visitor;
1111
use rustc_hir::{Expr, ExprKind, HirId, LangItem, Node, QPath, is_range_literal};
1212
use rustc_hir_analysis::check::potentially_plural_count;
13-
use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, PermitVariants};
13+
use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, IsMethodCall, PermitVariants};
1414
use rustc_index::IndexVec;
1515
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk, TypeTrace};
1616
use rustc_middle::ty::adjustment::AllowTwoPhase;
@@ -195,6 +195,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
195195
call_span: Span,
196196
// Expression of the call site
197197
call_expr: &'tcx hir::Expr<'tcx>,
198+
is_method: IsMethodCall,
198199
// Types (as defined in the *signature* of the target function)
199200
formal_input_tys: &[Ty<'tcx>],
200201
formal_output: Ty<'tcx>,
@@ -206,7 +207,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
206207
c_variadic: bool,
207208
// Whether the arguments have been bundled in a tuple (ex: closures)
208209
tuple_arguments: TupleArgumentsFlag,
209-
// The DefId for the function being called, for better error messages
210+
// The DefId for the function being called, for callee bound checks and
211+
// better error messages
210212
fn_def_id: Option<DefId>,
211213
) {
212214
let tcx = self.tcx;
@@ -326,8 +328,83 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
326328

327329
let mut err_code = E0061;
328330

331+
let mut expected_meets_callee_bounds = Vec::with_capacity(formal_input_tys.len());
332+
expected_meets_callee_bounds.resize(formal_input_tys.len(), true);
333+
334+
// Check whether the expected inputs satisfy the callee's where bounds.
335+
// This is skipped for the old solver: attempting trait solving there can
336+
// trigger an overflow, which is a fatal error in the old solver but is
337+
// treated as mere ambiguity by the next solver.
338+
if self.next_trait_solver()
339+
&& let Some(expected_input_tys) = &expected_input_tys
340+
&& let Some(fn_def_id) = fn_def_id
341+
// We don't need to check bounds for closures as they are already in the current
342+
// body's param env.
343+
&& self.tcx.def_kind(fn_def_id) != DefKind::Closure
344+
{
345+
self.probe(|_| {
346+
let new_args = self.fresh_args_for_item(call_span, fn_def_id);
347+
let fn_sig = self.tcx.fn_sig(fn_def_id).instantiate(self.tcx, new_args);
348+
let fn_sig = self.instantiate_binder_with_fresh_vars(
349+
call_span,
350+
BoundRegionConversionTime::FnCall,
351+
fn_sig,
352+
);
353+
let ocx = ObligationCtxt::new(self);
354+
let origin = self.misc(call_span);
355+
let fn_sig = ocx.normalize(&origin, self.param_env, fn_sig);
356+
357+
let bound_input_tys = fn_sig.inputs();
358+
let bound_input_tys = if is_method == IsMethodCall::Yes {
359+
&bound_input_tys[1..]
360+
} else {
361+
&bound_input_tys[..]
362+
};
363+
364+
let fn_bounds = self.tcx.predicates_of(fn_def_id).instantiate(self.tcx, new_args);
365+
let fn_bounds = traits::predicates_for_generics(
366+
|_, sp| self.misc(sp),
367+
self.param_env,
368+
fn_bounds,
369+
);
370+
ocx.register_obligations(fn_bounds);
371+
372+
// perf: We reuse this by cloning rather than repeating the above lines
373+
let preds = ocx.into_pending_obligations();
374+
375+
assert_eq!(bound_input_tys.len(), formal_input_tys.len(),);
376+
for idx in 0..formal_input_tys.len() {
377+
let meets_bounds = self
378+
.probe(|_| {
379+
let ocx = ObligationCtxt::new(self);
380+
ocx.register_obligations(preds.clone());
381+
ocx.eq(
382+
&origin,
383+
self.param_env,
384+
bound_input_tys[idx],
385+
expected_input_tys[idx],
386+
)?;
387+
if ocx.try_evaluate_obligations().is_empty() {
388+
Ok(())
389+
} else {
390+
Err(TypeError::Mismatch)
391+
}
392+
})
393+
.is_ok();
394+
expected_meets_callee_bounds[idx] = meets_bounds;
395+
}
396+
});
397+
}
398+
329399
// If the arguments should be wrapped in a tuple (ex: closures), unwrap them here
330400
let (formal_input_tys, expected_input_tys) = if tuple_arguments == TupleArguments {
401+
// Since the expected inputs are unpacked from a single tuple,
402+
// each input meets the callee bounds if and only if the tuple does.
403+
expected_meets_callee_bounds.resize(
404+
provided_args.len(),
405+
expected_meets_callee_bounds.first().copied().unwrap_or(true),
406+
);
407+
331408
let tuple_type = self.structurally_resolve_type(call_span, formal_input_tys[0]);
332409
match tuple_type.kind() {
333410
// We expected a tuple and got a tuple
@@ -390,7 +467,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
390467
// We're on the happy path here, so we'll do a more involved check and write back types
391468
// To check compatibility, we'll do 3 things:
392469
// 1. Unify the provided argument with the expected type
393-
let expectation = Expectation::rvalue_hint(self, expected_input_ty);
470+
let expectation = if expected_meets_callee_bounds[idx] {
471+
Expectation::rvalue_hint(self, expected_input_ty)
472+
} else {
473+
// If the expected input does not satisfy the callee's bounds, we must
474+
// weaken the expectation; otherwise, coercing to a type that violates
475+
// those bounds would result in a type mismatch.
476+
// See https://github.com/rust-lang/rust/issues/149379.
477+
Expectation::ExpectRvalueLikeUnsized(expected_input_ty)
478+
};
394479

395480
let checked_ty = self.check_expr_with_expectation(provided_arg, expectation);
396481

tests/ui/coercion/fudge-inference/expectated-input-not-satisfying-fn-bounds-issue-149881.current.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0277]: the size for values of type `[{integer}]` cannot be known at compilation time
2-
--> $DIR/expectated-input-not-satisfying-fn-bounds-issue-149881.rs:15:24
2+
--> $DIR/expectated-input-not-satisfying-fn-bounds-issue-149881.rs:16:24
33
|
44
LL | <[_]>::into_vec(id(Box::new([0, 1, 2])));
55
| -- ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
@@ -8,7 +8,7 @@ LL | <[_]>::into_vec(id(Box::new([0, 1, 2])));
88
|
99
= help: the trait `Sized` is not implemented for `[{integer}]`
1010
note: required by an implicit `Sized` bound in `id`
11-
--> $DIR/expectated-input-not-satisfying-fn-bounds-issue-149881.rs:10:7
11+
--> $DIR/expectated-input-not-satisfying-fn-bounds-issue-149881.rs:11:7
1212
|
1313
LL | fn id<T>(x: Box<T>) -> Box<T> {
1414
| ^ required by the implicit `Sized` requirement on this type parameter in `id`

tests/ui/coercion/fudge-inference/expectated-input-not-satisfying-fn-bounds-issue-149881.next.stderr

Lines changed: 0 additions & 22 deletions
This file was deleted.

tests/ui/coercion/fudge-inference/expectated-input-not-satisfying-fn-bounds-issue-149881.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//@ revisions: current next
22
//@ ignore-compare-mode-next-solver (explicit revisions)
33
//@[next] compile-flags: -Znext-solver
4+
//@[next] check-pass
45

56
// FIXME(#149379): This should pass, but fails due to fudged expactation
67
// types which are potentially not well-formed or for whom the function
@@ -13,5 +14,5 @@ fn id<T>(x: Box<T>) -> Box<T> {
1314

1415
fn main() {
1516
<[_]>::into_vec(id(Box::new([0, 1, 2])));
16-
//~^ ERROR: the size for values of type `[{integer}]` cannot be known at compilation time
17+
//[current]~^ ERROR: the size for values of type `[{integer}]` cannot be known at compilation time
1718
}

tests/ui/coercion/fudge-inference/expectated-input-not-satisfying-fn-bounds-issue-89299.current.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0277]: `dyn Trait + Send` cannot be unpinned
2-
--> $DIR/expectated-input-not-satisfying-fn-bounds-issue-89299.rs:20:27
2+
--> $DIR/expectated-input-not-satisfying-fn-bounds-issue-89299.rs:21:27
33
|
44
LL | let _x = Foo(Pin::new(&mut a));
55
| -------- ^^^^^^ the trait `Unpin` is not implemented for `dyn Trait + Send`

tests/ui/coercion/fudge-inference/expectated-input-not-satisfying-fn-bounds-issue-89299.next.stderr

Lines changed: 0 additions & 16 deletions
This file was deleted.

tests/ui/coercion/fudge-inference/expectated-input-not-satisfying-fn-bounds-issue-89299.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//@ revisions: current next
22
//@ ignore-compare-mode-next-solver (explicit revisions)
33
//@[next] compile-flags: -Znext-solver
4+
//@[next] check-pass
45

56
// FIXME(#149379): This should pass, but fails due to fudged expactation
67
// types which are potentially not well-formed or for whom the function
@@ -18,5 +19,5 @@ struct Foo<'a>(Pin<&'a mut (dyn Trait + Send)>);
1819
fn main() {
1920
let mut a = 1;
2021
let _x = Foo(Pin::new(&mut a));
21-
//~^ ERROR: `dyn Trait + Send` cannot be unpinned
22+
//[current]~^ ERROR: `dyn Trait + Send` cannot be unpinned
2223
}

tests/ui/coercion/fudge-inference/fn-ret-trait-object-propagated-to-inputs-issue-149379-2.current.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0277]: the size for values of type `dyn Send` cannot be known at compilation time
2-
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-2.rs:15:38
2+
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-2.rs:16:38
33
|
44
LL | let _: Box<dyn Send> = sized_box(Box::new(1));
55
| --------- ^^^^^^^^^^^ doesn't have a size known at compile-time
@@ -8,7 +8,7 @@ LL | let _: Box<dyn Send> = sized_box(Box::new(1));
88
|
99
= help: the trait `Sized` is not implemented for `dyn Send`
1010
note: required by an implicit `Sized` bound in `sized_box`
11-
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-2.rs:10:14
11+
--> $DIR/fn-ret-trait-object-propagated-to-inputs-issue-149379-2.rs:11:14
1212
|
1313
LL | fn sized_box<T>(x: Box<T>) -> Box<T> {
1414
| ^ required by the implicit `Sized` requirement on this type parameter in `sized_box`

0 commit comments

Comments
 (0)