Skip to content

Commit 95bec6e

Browse files
committed
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. 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 rust-lang#49593 (unblocking never_type).
1 parent a8a2a88 commit 95bec6e

File tree

6 files changed

+197
-55
lines changed

6 files changed

+197
-55
lines changed

src/librustc/infer/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1253,6 +1253,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
12531253
self.inlined_shallow_resolve(typ)
12541254
}
12551255

1256+
pub fn root_var(&self, var: ty::TyVid) -> ty::TyVid {
1257+
self.type_variables.borrow_mut().root_var(var)
1258+
}
1259+
12561260
pub fn resolve_type_vars_if_possible<T>(&self, value: &T) -> T
12571261
where
12581262
T: TypeFoldable<'tcx>,

src/librustc_typeck/check/closure.rs

+12-52
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;
@@ -222,6 +222,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
222222
let fulfillment_cx = self.fulfillment_cx.borrow();
223223
// Here `expected_ty` is known to be a type inference variable.
224224

225+
let expected_vid = self.root_var(expected_vid);
225226
let expected_sig = fulfillment_cx
226227
.pending_obligations()
227228
.iter()
@@ -235,13 +236,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
235236
// Given a Projection predicate, we can potentially infer
236237
// the complete signature.
237238
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-
})
239+
Some(()).filter(|()| {
240+
self.self_type_matches_expected_vid(trait_ref, expected_vid)
241+
}).and_then(|()| {
242+
self.deduce_sig_from_projection(
243+
Some(obligation.cause.span),
244+
proj_predicate
245+
)
246+
})
245247
} else {
246248
None
247249
}
@@ -252,34 +254,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
252254
// infer the kind. This can occur if there is a trait-reference
253255
// like `F : Fn<A>`. Note that due to subtyping we could encounter
254256
// 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-
})
257+
let expected_kind = self.obligations_for_self_ty(expected_vid)
258+
.filter_map(|tr| self.tcx.lang_items().fn_trait_kind(tr.def_id()))
283259
.fold(None, |best, cur| {
284260
Some(best.map_or(cur, |best| cmp::min(best, cur)))
285261
});
@@ -339,22 +315,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
339315
Some(ExpectedSig { cause_span, sig })
340316
}
341317

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-
358318
fn sig_of_closure(
359319
&self,
360320
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

+94-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;
@@ -134,6 +134,7 @@ use std::collections::hash_map::Entry;
134134
use std::cmp;
135135
use std::fmt::Display;
136136
use std::iter;
137+
use std::vec;
137138
use std::mem::replace;
138139
use std::ops::{self, Deref};
139140
use std::slice;
@@ -2731,6 +2732,97 @@ 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(v)) => {
2747+
let root_vid = self.root_var(v);
2748+
debug!("self_type_matches_expected_vid - root_vid={:?}", root_vid);
2749+
if root_vid == expected_vid {
2750+
true
2751+
} else {
2752+
false
2753+
}
2754+
}
2755+
_ => false
2756+
}
2757+
}
2758+
}
2759+
2760+
/// FIXME: impl Trait why u give me lifetime errors?
2761+
pub struct ObligationMapper<'a, 'gcx, 'tcx>(&'a FnCtxt<'a, 'gcx, 'tcx>, ty::TyVid);
2762+
2763+
impl<'a, 'gcx, 'tcx> FnOnce<(traits::PredicateObligation<'tcx>,)>
2764+
for ObligationMapper<'a, 'gcx, 'tcx>
2765+
{
2766+
type Output = Option<ty::PolyTraitRef<'tcx>>;
2767+
2768+
extern "rust-call" fn call_once(mut self, args: (traits::PredicateObligation<'tcx>,))
2769+
-> Self::Output {
2770+
self.call_mut(args)
2771+
}
2772+
}
2773+
2774+
impl<'a, 'gcx, 'tcx> FnMut<(traits::PredicateObligation<'tcx>,)>
2775+
for ObligationMapper<'a, 'gcx, 'tcx>
2776+
{
2777+
extern "rust-call" fn call_mut(&mut self, args: (traits::PredicateObligation<'tcx>,))
2778+
-> Self::Output {
2779+
match args.0.predicate {
2780+
ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref(self.0.tcx)),
2781+
ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()),
2782+
ty::Predicate::Subtype(..) => None,
2783+
ty::Predicate::RegionOutlives(..) => None,
2784+
ty::Predicate::TypeOutlives(..) => None,
2785+
ty::Predicate::WellFormed(..) => None,
2786+
ty::Predicate::ObjectSafe(..) => None,
2787+
ty::Predicate::ConstEvaluatable(..) => None,
2788+
// N.B., this predicate is created by breaking down a
2789+
// `ClosureType: FnFoo()` predicate, where
2790+
// `ClosureType` represents some `Closure`. It can't
2791+
// possibly be referring to the current closure,
2792+
// because we haven't produced the `Closure` for
2793+
// this closure yet; this is exactly why the other
2794+
// code is looking for a self type of a unresolved
2795+
// inference variable.
2796+
ty::Predicate::ClosureKind(..) => None,
2797+
}.filter(|tr| {
2798+
self.0.self_type_matches_expected_vid(*tr, self.1)
2799+
})
2800+
}
2801+
}
2802+
2803+
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
2804+
fn obligations_for_self_ty<'b>(&'b self, self_ty: ty::TyVid)
2805+
-> iter::FilterMap<vec::IntoIter<traits::PredicateObligation<'tcx>>,
2806+
ObligationMapper<'b, 'gcx, 'tcx>>
2807+
{
2808+
let ty_var_root = self.root_var(self_ty);
2809+
debug!("obligations_for_self_ty: self_ty={:?} ty_var_root={:?} pending_obligations={:?}",
2810+
self_ty, ty_var_root,
2811+
self.fulfillment_cx.borrow().pending_obligations());
2812+
2813+
self.fulfillment_cx
2814+
.borrow()
2815+
.pending_obligations()
2816+
.into_iter()
2817+
.filter_map(ObligationMapper(self, ty_var_root))
2818+
}
2819+
2820+
fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool {
2821+
self.obligations_for_self_ty(self_ty).any(|tr| {
2822+
Some(tr.def_id()) == self.tcx.lang_items().sized_trait()
2823+
})
2824+
}
2825+
27342826
/// Generic function that factors out common logic from function calls,
27352827
/// method calls and overloaded operators.
27362828
fn check_argument_types(&self,

src/librustc_typeck/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -75,13 +75,15 @@ This API is completely unstable and subject to change.
7575
#![feature(box_syntax)]
7676
#![feature(crate_visibility_modifier)]
7777
#![feature(exhaustive_patterns)]
78+
#![feature(fn_traits)]
7879
#![feature(nll)]
7980
#![feature(quote)]
8081
#![feature(refcell_replace_swap)]
8182
#![feature(rustc_diagnostic_macros)]
8283
#![feature(slice_patterns)]
8384
#![feature(slice_sort_by_cached_key)]
8485
#![feature(never_type)]
86+
#![feature(unboxed_closures)]
8587

8688
#![recursion_limit="256"]
8789

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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::char::ParseCharError; /* some Error */
18+
19+
fn raw_ptr_box<T>(t: T) -> *mut T {
20+
panic!()
21+
}
22+
23+
fn foo(x: !) -> Box<Error> {
24+
/* *mut $0 is coerced to *mut Error here */ Box::<_ /* ! */>::new(x)
25+
}
26+
27+
fn foo_raw_ptr(x: !) -> *mut Error {
28+
/* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x)
29+
}
30+
31+
fn no_coercion(d: *mut Error) -> *mut 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 /* : Box<S> */ = None;
45+
let mut first_iter = false;
46+
loop {
47+
if !first_iter {
48+
let y: Box<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+
57+
fn main() {
58+
}

0 commit comments

Comments
 (0)