Skip to content

Commit 3b1845c

Browse files
committed
Auto merge of #56219 - arielb1:never-coerce-box, r=nikomatsakis
trigger unsized coercions keyed on Sized bounds This PR causes unsized coercions to not be disabled by `$0: Unsize<dyn Object>` coercion obligations when we have an `$0: Sized` obligation somewhere. This should be mostly backwards-compatible, because in these cases not doing the unsize coercion should have caused the `$0: Sized` obligation to fail. Note that `X: Unsize<dyn Object>` obligations can't fail *as obligations* if `X: Sized` holds, so this still maintains some version of monotonicity (I think that an unsized coercion can't be converted to no coercion by unifying type variables). Fixes #49593 (unblocking never_type). r? @eddyb cc @nikomatsakis
2 parents d99a320 + 5b74438 commit 3b1845c

File tree

5 files changed

+172
-65
lines changed

5 files changed

+172
-65
lines changed

src/librustc/infer/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1270,6 +1270,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
12701270
self.inlined_shallow_resolve(typ)
12711271
}
12721272

1273+
pub fn root_var(&self, var: ty::TyVid) -> ty::TyVid {
1274+
self.type_variables.borrow_mut().root_var(var)
1275+
}
1276+
12731277
pub fn resolve_type_vars_if_possible<T>(&self, value: &T) -> T
12741278
where
12751279
T: TypeFoldable<'tcx>,

src/librustc_typeck/check/closure.rs

+10-62
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use rustc::infer::LateBoundRegionConversionTime;
2020
use rustc::infer::type_variable::TypeVariableOrigin;
2121
use rustc::traits::Obligation;
2222
use rustc::traits::error_reporting::ArgKind;
23-
use rustc::ty::{self, ToPolyTraitRef, Ty, GenericParamDefKind};
23+
use rustc::ty::{self, Ty, GenericParamDefKind};
2424
use rustc::ty::fold::TypeFoldable;
2525
use rustc::ty::subst::Substs;
2626
use std::cmp;
@@ -219,13 +219,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
219219
&self,
220220
expected_vid: ty::TyVid,
221221
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
222-
let fulfillment_cx = self.fulfillment_cx.borrow();
223-
// Here `expected_ty` is known to be a type inference variable.
224-
225-
let expected_sig = fulfillment_cx
226-
.pending_obligations()
227-
.iter()
228-
.filter_map(|obligation| {
222+
let expected_sig = self.obligations_for_self_ty(expected_vid)
223+
.find_map(|(_, obligation)| {
229224
debug!(
230225
"deduce_expectations_from_obligations: obligation.predicate={:?}",
231226
obligation.predicate
@@ -234,52 +229,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
234229
if let ty::Predicate::Projection(ref proj_predicate) = obligation.predicate {
235230
// Given a Projection predicate, we can potentially infer
236231
// the complete signature.
237-
let trait_ref = proj_predicate.to_poly_trait_ref(self.tcx);
238-
self.self_type_matches_expected_vid(trait_ref, expected_vid)
239-
.and_then(|_| {
240-
self.deduce_sig_from_projection(
241-
Some(obligation.cause.span),
242-
proj_predicate
243-
)
244-
})
232+
self.deduce_sig_from_projection(
233+
Some(obligation.cause.span),
234+
proj_predicate
235+
)
245236
} else {
246237
None
247238
}
248-
})
249-
.next();
239+
});
250240

251241
// Even if we can't infer the full signature, we may be able to
252242
// infer the kind. This can occur if there is a trait-reference
253243
// like `F : Fn<A>`. Note that due to subtyping we could encounter
254244
// many viable options, so pick the most restrictive.
255-
let expected_kind = fulfillment_cx
256-
.pending_obligations()
257-
.iter()
258-
.filter_map(|obligation| {
259-
let opt_trait_ref = match obligation.predicate {
260-
ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref(self.tcx)),
261-
ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()),
262-
ty::Predicate::Subtype(..) => None,
263-
ty::Predicate::RegionOutlives(..) => None,
264-
ty::Predicate::TypeOutlives(..) => None,
265-
ty::Predicate::WellFormed(..) => None,
266-
ty::Predicate::ObjectSafe(..) => None,
267-
ty::Predicate::ConstEvaluatable(..) => None,
268-
269-
// N.B., this predicate is created by breaking down a
270-
// `ClosureType: FnFoo()` predicate, where
271-
// `ClosureType` represents some `Closure`. It can't
272-
// possibly be referring to the current closure,
273-
// because we haven't produced the `Closure` for
274-
// this closure yet; this is exactly why the other
275-
// code is looking for a self type of a unresolved
276-
// inference variable.
277-
ty::Predicate::ClosureKind(..) => None,
278-
};
279-
opt_trait_ref
280-
.and_then(|tr| self.self_type_matches_expected_vid(tr, expected_vid))
281-
.and_then(|tr| self.tcx.lang_items().fn_trait_kind(tr.def_id()))
282-
})
245+
let expected_kind = self.obligations_for_self_ty(expected_vid)
246+
.filter_map(|(tr, _)| self.tcx.lang_items().fn_trait_kind(tr.def_id()))
283247
.fold(None, |best, cur| {
284248
Some(best.map_or(cur, |best| cmp::min(best, cur)))
285249
});
@@ -339,22 +303,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
339303
Some(ExpectedSig { cause_span, sig })
340304
}
341305

342-
fn self_type_matches_expected_vid(
343-
&self,
344-
trait_ref: ty::PolyTraitRef<'tcx>,
345-
expected_vid: ty::TyVid,
346-
) -> Option<ty::PolyTraitRef<'tcx>> {
347-
let self_ty = self.shallow_resolve(trait_ref.self_ty());
348-
debug!(
349-
"self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})",
350-
trait_ref, self_ty
351-
);
352-
match self_ty.sty {
353-
ty::Infer(ty::TyVar(v)) if expected_vid == v => Some(trait_ref),
354-
_ => None,
355-
}
356-
}
357-
358306
fn sig_of_closure(
359307
&self,
360308
expr_def_id: DefId,

src/librustc_typeck/check/coercion.rs

+27-1
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,33 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
579579
};
580580
match selcx.select(&obligation.with(trait_ref)) {
581581
// Uncertain or unimplemented.
582-
Ok(None) |
582+
Ok(None) => {
583+
if trait_ref.def_id() == unsize_did {
584+
let trait_ref = self.resolve_type_vars_if_possible(&trait_ref);
585+
let self_ty = trait_ref.skip_binder().self_ty();
586+
let unsize_ty = trait_ref.skip_binder().input_types().nth(1).unwrap();
587+
debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_ref);
588+
match (&self_ty.sty, &unsize_ty.sty) {
589+
(ty::Infer(ty::TyVar(v)),
590+
ty::Dynamic(..)) if self.type_var_is_sized(*v) => {
591+
debug!("coerce_unsized: have sized infer {:?}", v);
592+
coercion.obligations.push(obligation);
593+
// `$0: Unsize<dyn Trait>` where we know that `$0: Sized`, try going
594+
// for unsizing.
595+
}
596+
_ => {
597+
// Some other case for `$0: Unsize<Something>`. Note that we
598+
// hit this case even if `Something` is a sized type, so just
599+
// don't do the coercion.
600+
debug!("coerce_unsized: ambiguous unsize");
601+
return Err(TypeError::Mismatch);
602+
}
603+
}
604+
} else {
605+
debug!("coerce_unsized: early return - ambiguous");
606+
return Err(TypeError::Mismatch);
607+
}
608+
}
583609
Err(traits::Unimplemented) => {
584610
debug!("coerce_unsized: early return - can't prove obligation");
585611
return Err(TypeError::Mismatch);

src/librustc_typeck/check/mod.rs

+69-2
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,8 @@ use rustc::mir::interpret::{ConstValue, GlobalId};
113113
use rustc::ty::subst::{CanonicalUserSubsts, UnpackedKind, Subst, Substs,
114114
UserSelfTy, UserSubsts};
115115
use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
116-
use rustc::ty::{self, AdtKind, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate,
117-
RegionKind};
116+
use rustc::ty::{self, AdtKind, Ty, TyCtxt, GenericParamDefKind, RegionKind, Visibility,
117+
ToPolyTraitRef, ToPredicate};
118118
use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
119119
use rustc::ty::fold::TypeFoldable;
120120
use rustc::ty::query::Providers;
@@ -142,6 +142,7 @@ use require_c_abi_if_variadic;
142142
use session::{CompileIncomplete, config, Session};
143143
use TypeAndSubsts;
144144
use lint;
145+
use util::captures::Captures;
145146
use util::common::{ErrorReported, indenter};
146147
use util::nodemap::{DefIdMap, DefIdSet, FxHashMap, FxHashSet, NodeMap};
147148

@@ -2731,6 +2732,72 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
27312732
method.sig.output()
27322733
}
27332734

2735+
fn self_type_matches_expected_vid(
2736+
&self,
2737+
trait_ref: ty::PolyTraitRef<'tcx>,
2738+
expected_vid: ty::TyVid,
2739+
) -> bool {
2740+
let self_ty = self.shallow_resolve(trait_ref.self_ty());
2741+
debug!(
2742+
"self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?}, expected_vid={:?})",
2743+
trait_ref, self_ty, expected_vid
2744+
);
2745+
match self_ty.sty {
2746+
ty::Infer(ty::TyVar(found_vid)) => {
2747+
// FIXME: consider using `sub_root_var` here so we
2748+
// can see through subtyping.
2749+
let found_vid = self.root_var(found_vid);
2750+
debug!("self_type_matches_expected_vid - found_vid={:?}", found_vid);
2751+
expected_vid == found_vid
2752+
}
2753+
_ => false
2754+
}
2755+
}
2756+
2757+
fn obligations_for_self_ty<'b>(&'b self, self_ty: ty::TyVid)
2758+
-> impl Iterator<Item=(ty::PolyTraitRef<'tcx>, traits::PredicateObligation<'tcx>)>
2759+
+ Captures<'gcx> + 'b
2760+
{
2761+
// FIXME: consider using `sub_root_var` here so we
2762+
// can see through subtyping.
2763+
let ty_var_root = self.root_var(self_ty);
2764+
debug!("obligations_for_self_ty: self_ty={:?} ty_var_root={:?} pending_obligations={:?}",
2765+
self_ty, ty_var_root,
2766+
self.fulfillment_cx.borrow().pending_obligations());
2767+
2768+
self.fulfillment_cx
2769+
.borrow()
2770+
.pending_obligations()
2771+
.into_iter()
2772+
.filter_map(move |obligation| match obligation.predicate {
2773+
ty::Predicate::Projection(ref data) =>
2774+
Some((data.to_poly_trait_ref(self.tcx), obligation)),
2775+
ty::Predicate::Trait(ref data) =>
2776+
Some((data.to_poly_trait_ref(), obligation)),
2777+
ty::Predicate::Subtype(..) => None,
2778+
ty::Predicate::RegionOutlives(..) => None,
2779+
ty::Predicate::TypeOutlives(..) => None,
2780+
ty::Predicate::WellFormed(..) => None,
2781+
ty::Predicate::ObjectSafe(..) => None,
2782+
ty::Predicate::ConstEvaluatable(..) => None,
2783+
// N.B., this predicate is created by breaking down a
2784+
// `ClosureType: FnFoo()` predicate, where
2785+
// `ClosureType` represents some `Closure`. It can't
2786+
// possibly be referring to the current closure,
2787+
// because we haven't produced the `Closure` for
2788+
// this closure yet; this is exactly why the other
2789+
// code is looking for a self type of a unresolved
2790+
// inference variable.
2791+
ty::Predicate::ClosureKind(..) => None,
2792+
}).filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root))
2793+
}
2794+
2795+
fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool {
2796+
self.obligations_for_self_ty(self_ty).any(|(tr, _)| {
2797+
Some(tr.def_id()) == self.tcx.lang_items().sized_trait()
2798+
})
2799+
}
2800+
27342801
/// Generic function that factors out common logic from function calls,
27352802
/// method calls and overloaded operators.
27362803
fn check_argument_types(&self,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// compile-pass
12+
13+
#![feature(never_type)]
14+
#![allow(unreachable_code)]
15+
16+
use std::error::Error;
17+
use std::mem;
18+
19+
fn raw_ptr_box<T>(t: T) -> *mut T {
20+
panic!()
21+
}
22+
23+
fn foo(x: !) -> Box<dyn Error> {
24+
/* *mut $0 is coerced to Box<dyn Error> here */ Box::<_ /* ! */>::new(x)
25+
}
26+
27+
fn foo_raw_ptr(x: !) -> *mut dyn Error {
28+
/* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x)
29+
}
30+
31+
fn no_coercion(d: *mut dyn Error) -> *mut dyn Error {
32+
/* an unsize coercion won't compile here, and it is indeed not used
33+
because there is nothing requiring the _ to be Sized */
34+
d as *mut _
35+
}
36+
37+
trait Xyz {}
38+
struct S;
39+
struct T;
40+
impl Xyz for S {}
41+
impl Xyz for T {}
42+
43+
fn foo_no_never() {
44+
let mut x /* : Option<S> */ = None;
45+
let mut first_iter = false;
46+
loop {
47+
if !first_iter {
48+
let y: Box<dyn Xyz>
49+
= /* Box<$0> is coerced to Box<Xyz> here */ Box::new(x.unwrap());
50+
}
51+
52+
x = Some(S);
53+
first_iter = true;
54+
}
55+
56+
let mut y : Option<S> = None;
57+
// assert types are equal
58+
mem::swap(&mut x, &mut y);
59+
}
60+
61+
fn main() {
62+
}

0 commit comments

Comments
 (0)