From 95bec6ed0987227be8228ea87e002a17c1cc8ed6 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 25 Nov 2018 16:14:54 +0200 Subject: [PATCH 1/5] trigger unsized coercions keyed on Sized bounds This PR causes unsized coercions to not be disabled by `$0: Unsize` coercion obligations when we have an `$0: Sized` obligation somewhere. Note that `X: Unsize` 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). --- src/librustc/infer/mod.rs | 4 + src/librustc_typeck/check/closure.rs | 64 +++---------- src/librustc_typeck/check/coercion.rs | 28 +++++- src/librustc_typeck/check/mod.rs | 96 ++++++++++++++++++- src/librustc_typeck/lib.rs | 2 + .../coercion/coerce-issue-49593-box-never.rs | 58 +++++++++++ 6 files changed, 197 insertions(+), 55 deletions(-) create mode 100644 src/test/ui/coercion/coerce-issue-49593-box-never.rs diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index b1a13354b7cdb..92e0a0a763d23 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1253,6 +1253,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.inlined_shallow_resolve(typ) } + pub fn root_var(&self, var: ty::TyVid) -> ty::TyVid { + self.type_variables.borrow_mut().root_var(var) + } + pub fn resolve_type_vars_if_possible(&self, value: &T) -> T where T: TypeFoldable<'tcx>, diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index be15503e47906..8971e1aa058ff 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -20,7 +20,7 @@ use rustc::infer::LateBoundRegionConversionTime; use rustc::infer::type_variable::TypeVariableOrigin; use rustc::traits::Obligation; use rustc::traits::error_reporting::ArgKind; -use rustc::ty::{self, ToPolyTraitRef, Ty, GenericParamDefKind}; +use rustc::ty::{self, Ty, GenericParamDefKind}; use rustc::ty::fold::TypeFoldable; use rustc::ty::subst::Substs; use std::cmp; @@ -222,6 +222,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let fulfillment_cx = self.fulfillment_cx.borrow(); // Here `expected_ty` is known to be a type inference variable. + let expected_vid = self.root_var(expected_vid); let expected_sig = fulfillment_cx .pending_obligations() .iter() @@ -235,13 +236,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Given a Projection predicate, we can potentially infer // the complete signature. let trait_ref = proj_predicate.to_poly_trait_ref(self.tcx); - self.self_type_matches_expected_vid(trait_ref, expected_vid) - .and_then(|_| { - self.deduce_sig_from_projection( - Some(obligation.cause.span), - proj_predicate - ) - }) + Some(()).filter(|()| { + self.self_type_matches_expected_vid(trait_ref, expected_vid) + }).and_then(|()| { + self.deduce_sig_from_projection( + Some(obligation.cause.span), + proj_predicate + ) + }) } else { None } @@ -252,34 +254,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // infer the kind. This can occur if there is a trait-reference // like `F : Fn`. Note that due to subtyping we could encounter // many viable options, so pick the most restrictive. - let expected_kind = fulfillment_cx - .pending_obligations() - .iter() - .filter_map(|obligation| { - let opt_trait_ref = match obligation.predicate { - ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref(self.tcx)), - ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()), - ty::Predicate::Subtype(..) => None, - ty::Predicate::RegionOutlives(..) => None, - ty::Predicate::TypeOutlives(..) => None, - ty::Predicate::WellFormed(..) => None, - ty::Predicate::ObjectSafe(..) => None, - ty::Predicate::ConstEvaluatable(..) => None, - - // N.B., this predicate is created by breaking down a - // `ClosureType: FnFoo()` predicate, where - // `ClosureType` represents some `Closure`. It can't - // possibly be referring to the current closure, - // because we haven't produced the `Closure` for - // this closure yet; this is exactly why the other - // code is looking for a self type of a unresolved - // inference variable. - ty::Predicate::ClosureKind(..) => None, - }; - opt_trait_ref - .and_then(|tr| self.self_type_matches_expected_vid(tr, expected_vid)) - .and_then(|tr| self.tcx.lang_items().fn_trait_kind(tr.def_id())) - }) + let expected_kind = self.obligations_for_self_ty(expected_vid) + .filter_map(|tr| self.tcx.lang_items().fn_trait_kind(tr.def_id())) .fold(None, |best, cur| { Some(best.map_or(cur, |best| cmp::min(best, cur))) }); @@ -339,22 +315,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Some(ExpectedSig { cause_span, sig }) } - fn self_type_matches_expected_vid( - &self, - trait_ref: ty::PolyTraitRef<'tcx>, - expected_vid: ty::TyVid, - ) -> Option> { - let self_ty = self.shallow_resolve(trait_ref.self_ty()); - debug!( - "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})", - trait_ref, self_ty - ); - match self_ty.sty { - ty::Infer(ty::TyVar(v)) if expected_vid == v => Some(trait_ref), - _ => None, - } - } - fn sig_of_closure( &self, expr_def_id: DefId, diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 8d844fe3a69e4..6832a6d2b5687 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -579,7 +579,33 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { }; match selcx.select(&obligation.with(trait_ref)) { // Uncertain or unimplemented. - Ok(None) | + Ok(None) => { + if trait_ref.def_id() == unsize_did { + let trait_ref = self.resolve_type_vars_if_possible(&trait_ref); + let self_ty = trait_ref.skip_binder().self_ty(); + let unsize_ty = trait_ref.skip_binder().input_types().nth(1).unwrap(); + debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_ref); + match (&self_ty.sty, &unsize_ty.sty) { + (ty::Infer(ty::TyVar(v)), + ty::Dynamic(..)) if self.type_var_is_sized(*v) => { + debug!("coerce_unsized: have sized infer {:?}", v); + coercion.obligations.push(obligation); + // `$0: Unsize` where we know that `$0: Sized`, try going + // for unsizing. + } + _ => { + // Some other case for `$0: Unsize`. Note that we + // hit this case even if `Something` is a sized type, so just + // don't do the coercion. + debug!("coerce_unsized: ambiguous unsize"); + return Err(TypeError::Mismatch); + } + } + } else { + debug!("coerce_unsized: early return - ambiguous"); + return Err(TypeError::Mismatch); + } + } Err(traits::Unimplemented) => { debug!("coerce_unsized: early return - can't prove obligation"); return Err(TypeError::Mismatch); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 957c8d9f19f0e..e3770cee72ff7 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -113,8 +113,8 @@ use rustc::mir::interpret::{ConstValue, GlobalId}; use rustc::ty::subst::{CanonicalUserSubsts, UnpackedKind, Subst, Substs, UserSelfTy, UserSubsts}; use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine}; -use rustc::ty::{self, AdtKind, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate, - RegionKind}; +use rustc::ty::{self, AdtKind, Ty, TyCtxt, GenericParamDefKind, RegionKind, Visibility, + ToPolyTraitRef, ToPredicate}; use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc::ty::fold::TypeFoldable; use rustc::ty::query::Providers; @@ -134,6 +134,7 @@ use std::collections::hash_map::Entry; use std::cmp; use std::fmt::Display; use std::iter; +use std::vec; use std::mem::replace; use std::ops::{self, Deref}; use std::slice; @@ -2731,6 +2732,97 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { method.sig.output() } + fn self_type_matches_expected_vid( + &self, + trait_ref: ty::PolyTraitRef<'tcx>, + expected_vid: ty::TyVid, + ) -> bool { + let self_ty = self.shallow_resolve(trait_ref.self_ty()); + debug!( + "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?}, expected_vid={:?})", + trait_ref, self_ty, expected_vid + ); + match self_ty.sty { + ty::Infer(ty::TyVar(v)) => { + let root_vid = self.root_var(v); + debug!("self_type_matches_expected_vid - root_vid={:?}", root_vid); + if root_vid == expected_vid { + true + } else { + false + } + } + _ => false + } + } +} + +/// FIXME: impl Trait why u give me lifetime errors? +pub struct ObligationMapper<'a, 'gcx, 'tcx>(&'a FnCtxt<'a, 'gcx, 'tcx>, ty::TyVid); + +impl<'a, 'gcx, 'tcx> FnOnce<(traits::PredicateObligation<'tcx>,)> + for ObligationMapper<'a, 'gcx, 'tcx> +{ + type Output = Option>; + + extern "rust-call" fn call_once(mut self, args: (traits::PredicateObligation<'tcx>,)) + -> Self::Output { + self.call_mut(args) + } +} + +impl<'a, 'gcx, 'tcx> FnMut<(traits::PredicateObligation<'tcx>,)> + for ObligationMapper<'a, 'gcx, 'tcx> +{ + extern "rust-call" fn call_mut(&mut self, args: (traits::PredicateObligation<'tcx>,)) + -> Self::Output { + match args.0.predicate { + ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref(self.0.tcx)), + ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()), + ty::Predicate::Subtype(..) => None, + ty::Predicate::RegionOutlives(..) => None, + ty::Predicate::TypeOutlives(..) => None, + ty::Predicate::WellFormed(..) => None, + ty::Predicate::ObjectSafe(..) => None, + ty::Predicate::ConstEvaluatable(..) => None, + // N.B., this predicate is created by breaking down a + // `ClosureType: FnFoo()` predicate, where + // `ClosureType` represents some `Closure`. It can't + // possibly be referring to the current closure, + // because we haven't produced the `Closure` for + // this closure yet; this is exactly why the other + // code is looking for a self type of a unresolved + // inference variable. + ty::Predicate::ClosureKind(..) => None, + }.filter(|tr| { + self.0.self_type_matches_expected_vid(*tr, self.1) + }) + } +} + +impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { + fn obligations_for_self_ty<'b>(&'b self, self_ty: ty::TyVid) + -> iter::FilterMap>, + ObligationMapper<'b, 'gcx, 'tcx>> + { + let ty_var_root = self.root_var(self_ty); + debug!("obligations_for_self_ty: self_ty={:?} ty_var_root={:?} pending_obligations={:?}", + self_ty, ty_var_root, + self.fulfillment_cx.borrow().pending_obligations()); + + self.fulfillment_cx + .borrow() + .pending_obligations() + .into_iter() + .filter_map(ObligationMapper(self, ty_var_root)) + } + + fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool { + self.obligations_for_self_ty(self_ty).any(|tr| { + Some(tr.def_id()) == self.tcx.lang_items().sized_trait() + }) + } + /// Generic function that factors out common logic from function calls, /// method calls and overloaded operators. fn check_argument_types(&self, diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 8d6fb8b7f3948..5ecf24c4a1036 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -75,6 +75,7 @@ This API is completely unstable and subject to change. #![feature(box_syntax)] #![feature(crate_visibility_modifier)] #![feature(exhaustive_patterns)] +#![feature(fn_traits)] #![feature(nll)] #![feature(quote)] #![feature(refcell_replace_swap)] @@ -82,6 +83,7 @@ This API is completely unstable and subject to change. #![feature(slice_patterns)] #![feature(slice_sort_by_cached_key)] #![feature(never_type)] +#![feature(unboxed_closures)] #![recursion_limit="256"] diff --git a/src/test/ui/coercion/coerce-issue-49593-box-never.rs b/src/test/ui/coercion/coerce-issue-49593-box-never.rs new file mode 100644 index 0000000000000..7cdc6c8c4a4c8 --- /dev/null +++ b/src/test/ui/coercion/coerce-issue-49593-box-never.rs @@ -0,0 +1,58 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-pass + +#![feature(never_type)] +#![allow(unreachable_code)] + +use std::error::Error; +use std::char::ParseCharError; /* some Error */ + +fn raw_ptr_box(t: T) -> *mut T { + panic!() +} + +fn foo(x: !) -> Box { + /* *mut $0 is coerced to *mut Error here */ Box::<_ /* ! */>::new(x) +} + +fn foo_raw_ptr(x: !) -> *mut Error { + /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x) +} + +fn no_coercion(d: *mut Error) -> *mut Error { + /* an unsize coercion won't compile here, and it is indeed not used + because there is nothing requiring the _ to be Sized */ + d as *mut _ +} + +trait Xyz {} +struct S; +struct T; +impl Xyz for S {} +impl Xyz for T {} + +fn foo_no_never() { + let mut x /* : Box */ = None; + let mut first_iter = false; + loop { + if !first_iter { + let y: Box + = /* Box<$0> is coerced to Box here */ Box::new(x.unwrap()); + } + + x = Some(S); + first_iter = true; + } +} + +fn main() { +} From 78f7e854f981c5f0c23f0eaf4c750ce1aa581ac6 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 25 Nov 2018 23:51:23 +0200 Subject: [PATCH 2/5] address review comments --- src/librustc_typeck/check/mod.rs | 12 ++++-------- .../coercion/coerce-issue-49593-box-never.rs | 18 +++++++++++------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e3770cee72ff7..8f044f9a7c35f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2743,14 +2743,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { trait_ref, self_ty, expected_vid ); match self_ty.sty { - ty::Infer(ty::TyVar(v)) => { - let root_vid = self.root_var(v); - debug!("self_type_matches_expected_vid - root_vid={:?}", root_vid); - if root_vid == expected_vid { - true - } else { - false - } + ty::Infer(ty::TyVar(found_vid)) => { + let found_vid = self.root_var(found_vid); + debug!("self_type_matches_expected_vid - found_vid={:?}", found_vid); + expected_vid == found_vid } _ => false } diff --git a/src/test/ui/coercion/coerce-issue-49593-box-never.rs b/src/test/ui/coercion/coerce-issue-49593-box-never.rs index 7cdc6c8c4a4c8..407484e3d2665 100644 --- a/src/test/ui/coercion/coerce-issue-49593-box-never.rs +++ b/src/test/ui/coercion/coerce-issue-49593-box-never.rs @@ -14,21 +14,21 @@ #![allow(unreachable_code)] use std::error::Error; -use std::char::ParseCharError; /* some Error */ +use std::mem; fn raw_ptr_box(t: T) -> *mut T { panic!() } -fn foo(x: !) -> Box { - /* *mut $0 is coerced to *mut Error here */ Box::<_ /* ! */>::new(x) +fn foo(x: !) -> Box { + /* *mut $0 is coerced to Box here */ Box::<_ /* ! */>::new(x) } -fn foo_raw_ptr(x: !) -> *mut Error { +fn foo_raw_ptr(x: !) -> *mut dyn Error { /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x) } -fn no_coercion(d: *mut Error) -> *mut Error { +fn no_coercion(d: *mut dyn Error) -> *mut dyn Error { /* an unsize coercion won't compile here, and it is indeed not used because there is nothing requiring the _ to be Sized */ d as *mut _ @@ -41,17 +41,21 @@ impl Xyz for S {} impl Xyz for T {} fn foo_no_never() { - let mut x /* : Box */ = None; + let mut x /* : Option */ = None; let mut first_iter = false; loop { if !first_iter { - let y: Box + let y: Box = /* Box<$0> is coerced to Box here */ Box::new(x.unwrap()); } x = Some(S); first_iter = true; } + + let mut y : Option = None; + // assert types are equal + mem::replace(&mut x, &mut y); } fn main() { From f4dc1c5d64d5439ba8b70f93490d7dc8ee512c7e Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 26 Nov 2018 10:23:42 +0200 Subject: [PATCH 3/5] fix review comments, round 2 --- src/librustc_typeck/check/mod.rs | 72 ++++++------------- src/librustc_typeck/lib.rs | 2 - .../coercion/coerce-issue-49593-box-never.rs | 2 +- 3 files changed, 23 insertions(+), 53 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 8f044f9a7c35f..e8252f55735bc 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -134,7 +134,6 @@ use std::collections::hash_map::Entry; use std::cmp; use std::fmt::Display; use std::iter; -use std::vec; use std::mem::replace; use std::ops::{self, Deref}; use std::slice; @@ -143,6 +142,7 @@ use require_c_abi_if_variadic; use session::{CompileIncomplete, config, Session}; use TypeAndSubsts; use lint; +use util::captures::Captures; use util::common::{ErrorReported, indenter}; use util::nodemap::{DefIdMap, DefIdSet, FxHashMap, FxHashSet, NodeMap}; @@ -2751,55 +2751,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => false } } -} - -/// FIXME: impl Trait why u give me lifetime errors? -pub struct ObligationMapper<'a, 'gcx, 'tcx>(&'a FnCtxt<'a, 'gcx, 'tcx>, ty::TyVid); - -impl<'a, 'gcx, 'tcx> FnOnce<(traits::PredicateObligation<'tcx>,)> - for ObligationMapper<'a, 'gcx, 'tcx> -{ - type Output = Option>; - - extern "rust-call" fn call_once(mut self, args: (traits::PredicateObligation<'tcx>,)) - -> Self::Output { - self.call_mut(args) - } -} -impl<'a, 'gcx, 'tcx> FnMut<(traits::PredicateObligation<'tcx>,)> - for ObligationMapper<'a, 'gcx, 'tcx> -{ - extern "rust-call" fn call_mut(&mut self, args: (traits::PredicateObligation<'tcx>,)) - -> Self::Output { - match args.0.predicate { - ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref(self.0.tcx)), - ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()), - ty::Predicate::Subtype(..) => None, - ty::Predicate::RegionOutlives(..) => None, - ty::Predicate::TypeOutlives(..) => None, - ty::Predicate::WellFormed(..) => None, - ty::Predicate::ObjectSafe(..) => None, - ty::Predicate::ConstEvaluatable(..) => None, - // N.B., this predicate is created by breaking down a - // `ClosureType: FnFoo()` predicate, where - // `ClosureType` represents some `Closure`. It can't - // possibly be referring to the current closure, - // because we haven't produced the `Closure` for - // this closure yet; this is exactly why the other - // code is looking for a self type of a unresolved - // inference variable. - ty::Predicate::ClosureKind(..) => None, - }.filter(|tr| { - self.0.self_type_matches_expected_vid(*tr, self.1) - }) - } -} - -impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn obligations_for_self_ty<'b>(&'b self, self_ty: ty::TyVid) - -> iter::FilterMap>, - ObligationMapper<'b, 'gcx, 'tcx>> + -> impl Iterator> + Captures<'gcx> + 'b { let ty_var_root = self.root_var(self_ty); debug!("obligations_for_self_ty: self_ty={:?} ty_var_root={:?} pending_obligations={:?}", @@ -2810,12 +2764,30 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .borrow() .pending_obligations() .into_iter() - .filter_map(ObligationMapper(self, ty_var_root)) + .filter_map(move |obligation| match obligation.predicate { + ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref(self.tcx)), + ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()), + ty::Predicate::Subtype(..) => None, + ty::Predicate::RegionOutlives(..) => None, + ty::Predicate::TypeOutlives(..) => None, + ty::Predicate::WellFormed(..) => None, + ty::Predicate::ObjectSafe(..) => None, + ty::Predicate::ConstEvaluatable(..) => None, + // N.B., this predicate is created by breaking down a + // `ClosureType: FnFoo()` predicate, where + // `ClosureType` represents some `Closure`. It can't + // possibly be referring to the current closure, + // because we haven't produced the `Closure` for + // this closure yet; this is exactly why the other + // code is looking for a self type of a unresolved + // inference variable. + ty::Predicate::ClosureKind(..) => None, + }).filter(move |tr| self.self_type_matches_expected_vid(*tr, ty_var_root)) } fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool { self.obligations_for_self_ty(self_ty).any(|tr| { - Some(tr.def_id()) == self.tcx.lang_items().sized_trait() + Some(tr.def_id()) == self.tcx.lang_items().sized_trait() }) } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 5ecf24c4a1036..8d6fb8b7f3948 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -75,7 +75,6 @@ This API is completely unstable and subject to change. #![feature(box_syntax)] #![feature(crate_visibility_modifier)] #![feature(exhaustive_patterns)] -#![feature(fn_traits)] #![feature(nll)] #![feature(quote)] #![feature(refcell_replace_swap)] @@ -83,7 +82,6 @@ This API is completely unstable and subject to change. #![feature(slice_patterns)] #![feature(slice_sort_by_cached_key)] #![feature(never_type)] -#![feature(unboxed_closures)] #![recursion_limit="256"] diff --git a/src/test/ui/coercion/coerce-issue-49593-box-never.rs b/src/test/ui/coercion/coerce-issue-49593-box-never.rs index 407484e3d2665..bea8586452e55 100644 --- a/src/test/ui/coercion/coerce-issue-49593-box-never.rs +++ b/src/test/ui/coercion/coerce-issue-49593-box-never.rs @@ -55,7 +55,7 @@ fn foo_no_never() { let mut y : Option = None; // assert types are equal - mem::replace(&mut x, &mut y); + mem::swap(&mut x, &mut y); } fn main() { From eeb8c8d59c1ca43999a6d7bd5f46a0a54971303f Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 1 Dec 2018 14:27:45 +0200 Subject: [PATCH 4/5] cleanup `deduce_expectations_from_obligations` --- src/librustc_typeck/check/closure.rs | 28 ++++++++-------------------- src/librustc_typeck/check/mod.rs | 13 ++++++++----- 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 8971e1aa058ff..f599a2b2ece07 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -219,14 +219,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { &self, expected_vid: ty::TyVid, ) -> (Option>, Option) { - let fulfillment_cx = self.fulfillment_cx.borrow(); - // Here `expected_ty` is known to be a type inference variable. - - let expected_vid = self.root_var(expected_vid); - let expected_sig = fulfillment_cx - .pending_obligations() - .iter() - .filter_map(|obligation| { + let expected_sig = self.obligations_for_self_ty(expected_vid) + .find_map(|(_, obligation)| { debug!( "deduce_expectations_from_obligations: obligation.predicate={:?}", obligation.predicate @@ -235,27 +229,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let ty::Predicate::Projection(ref proj_predicate) = obligation.predicate { // Given a Projection predicate, we can potentially infer // the complete signature. - let trait_ref = proj_predicate.to_poly_trait_ref(self.tcx); - Some(()).filter(|()| { - self.self_type_matches_expected_vid(trait_ref, expected_vid) - }).and_then(|()| { - self.deduce_sig_from_projection( - Some(obligation.cause.span), - proj_predicate - ) - }) + self.deduce_sig_from_projection( + Some(obligation.cause.span), + proj_predicate + ) } else { None } - }) - .next(); + }); // Even if we can't infer the full signature, we may be able to // infer the kind. This can occur if there is a trait-reference // like `F : Fn`. Note that due to subtyping we could encounter // many viable options, so pick the most restrictive. let expected_kind = self.obligations_for_self_ty(expected_vid) - .filter_map(|tr| self.tcx.lang_items().fn_trait_kind(tr.def_id())) + .filter_map(|(tr, _)| self.tcx.lang_items().fn_trait_kind(tr.def_id())) .fold(None, |best, cur| { Some(best.map_or(cur, |best| cmp::min(best, cur))) }); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e8252f55735bc..a8711d73af8ca 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2753,7 +2753,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } fn obligations_for_self_ty<'b>(&'b self, self_ty: ty::TyVid) - -> impl Iterator> + Captures<'gcx> + 'b + -> impl Iterator, traits::PredicateObligation<'tcx>)> + + Captures<'gcx> + 'b { let ty_var_root = self.root_var(self_ty); debug!("obligations_for_self_ty: self_ty={:?} ty_var_root={:?} pending_obligations={:?}", @@ -2765,8 +2766,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .pending_obligations() .into_iter() .filter_map(move |obligation| match obligation.predicate { - ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref(self.tcx)), - ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()), + ty::Predicate::Projection(ref data) => + Some((data.to_poly_trait_ref(self.tcx), obligation)), + ty::Predicate::Trait(ref data) => + Some((data.to_poly_trait_ref(), obligation)), ty::Predicate::Subtype(..) => None, ty::Predicate::RegionOutlives(..) => None, ty::Predicate::TypeOutlives(..) => None, @@ -2782,11 +2785,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // code is looking for a self type of a unresolved // inference variable. ty::Predicate::ClosureKind(..) => None, - }).filter(move |tr| self.self_type_matches_expected_vid(*tr, ty_var_root)) + }).filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root)) } fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool { - self.obligations_for_self_ty(self_ty).any(|tr| { + self.obligations_for_self_ty(self_ty).any(|(tr, _)| { Some(tr.def_id()) == self.tcx.lang_items().sized_trait() }) } From 5b7443810794aa9f771ea26a5e72ae2b567481b0 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Wed, 19 Dec 2018 02:05:34 +0200 Subject: [PATCH 5/5] add comment about subtyping --- src/librustc_typeck/check/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a8711d73af8ca..872c494e63304 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2744,6 +2744,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ); match self_ty.sty { ty::Infer(ty::TyVar(found_vid)) => { + // FIXME: consider using `sub_root_var` here so we + // can see through subtyping. let found_vid = self.root_var(found_vid); debug!("self_type_matches_expected_vid - found_vid={:?}", found_vid); expected_vid == found_vid @@ -2756,6 +2758,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { -> impl Iterator, traits::PredicateObligation<'tcx>)> + Captures<'gcx> + 'b { + // FIXME: consider using `sub_root_var` here so we + // can see through subtyping. let ty_var_root = self.root_var(self_ty); debug!("obligations_for_self_ty: self_ty={:?} ty_var_root={:?} pending_obligations={:?}", self_ty, ty_var_root,