From c01bfbd02b57a1aa9d8a39cd907f799d23c2a230 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Tue, 12 Dec 2017 14:50:09 -0200 Subject: [PATCH 1/9] refactor `structurally_resolve_type` the `or_else` part was dead code. --- src/librustc_typeck/check/mod.rs | 44 ++++++++++---------------------- 1 file changed, 13 insertions(+), 31 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 6147743437b..cb80498f3e2 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4954,39 +4954,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }); } - fn structurally_resolve_type_or_else(&self, sp: Span, ty: Ty<'tcx>, f: F) - -> Ty<'tcx> - where F: Fn() -> Ty<'tcx> - { - let mut ty = self.resolve_type_vars_with_obligations(ty); - - if ty.is_ty_var() { - let alternative = f(); - - // If not, error. - if alternative.is_ty_var() || alternative.references_error() { - if !self.is_tainted_by_errors() { - type_error_struct!(self.tcx.sess, sp, ty, E0619, - "the type of this value must be known in this context") - .emit(); - } - self.demand_suptype(sp, self.tcx.types.err, ty); - ty = self.tcx.types.err; - } else { - self.demand_suptype(sp, alternative, ty); - ty = alternative; - } - } - - ty - } - - // Resolves `typ` by a single level if `typ` is a type variable. If no + // Resolves `typ` by a single level if `typ` is a type variable. If no // resolution is possible, then an error is reported. pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - self.structurally_resolve_type_or_else(sp, ty, || { - self.tcx.types.err - }) + let mut ty = self.resolve_type_vars_with_obligations(ty); + if ty.is_ty_var() { + // If not, error. + if !self.is_tainted_by_errors() { + type_error_struct!(self.tcx.sess, sp, ty, E0619, + "the type of this value must be known in this context") + .emit(); + } + self.demand_suptype(sp, self.tcx.types.err, ty); + ty = self.tcx.types.err; + } + ty } fn with_breakable_ctxt R, R>(&self, id: ast::NodeId, From 3d83fc914a0f116ad0e4412d5ccc0be24b3b7af2 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Wed, 13 Dec 2017 12:35:26 -0200 Subject: [PATCH 2/9] Lazy numeric fallback. This refactoring tries to make numeric fallback easier to reason about. Instead of applying all fallbacks at an arbitrary point in the middle of inference, we apply the fallback only when necessary and only for the variable that requires it, which for numeric fallback turns out to be just casts. The only visible consequence seems to be some error messages where instead of getting `i32` we get `{integer}` because we are less eager about fallback. The bigger goal is to make it easier to integrate user fallbacks into inference, if we ever figure that out. --- src/librustc/ty/sty.rs | 7 ++ src/librustc_typeck/check/cast.rs | 4 +- src/librustc_typeck/check/mod.rs | 110 +++++++++++------- .../derived-errors/issue-31997.rs | 4 +- .../interior-mutability.stderr | 12 +- .../ui/mismatched_types/issue-26480.stderr | 2 +- 6 files changed, 87 insertions(+), 52 deletions(-) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index db7e4fe45ef..d38ceb619e3 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1290,6 +1290,13 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + pub fn is_ty_infer(&self) -> bool { + match self.sty { + TyInfer(_) => true, + _ => false, + } + } + pub fn is_phantom_data(&self) -> bool { if let TyAdt(def, _) = self.sty { def.is_phantom_data() diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 48bd7b14fc9..bc157d6feea 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -392,8 +392,8 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } pub fn check(mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) { - self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty); - self.cast_ty = fcx.structurally_resolved_type(self.span, self.cast_ty); + self.expr_ty = fcx.resolved_type(self.span, self.expr_ty); + self.cast_ty = fcx.resolved_type(self.span, self.cast_ty); debug!("check_cast({}, {:?} as {:?})", self.expr.id, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index cb80498f3e2..aff96e39cfc 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -858,9 +858,8 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fcx }; - fcx.select_all_obligations_and_apply_defaults(); - fcx.closure_analyze(body); fcx.select_obligations_where_possible(); + fcx.closure_analyze(body); fcx.check_casts(); fcx.resolve_generator_interiors(def_id); fcx.select_all_obligations_or_error(); @@ -2129,13 +2128,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } /// Apply "fallbacks" to some types - /// unconstrained types get replaced with ! or () (depending on whether + /// unconstrained types get replaced with ! or () (depending on whether /// feature(never_type) is enabled), unconstrained ints with i32, and /// unconstrained floats with f64. fn default_type_parameters(&self) { - use rustc::ty::error::UnconstrainedNumeric::Neither; - use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; - // Defaulting inference variables becomes very dubious if we have // encountered type-checking errors. Therefore, if we think we saw // some errors in this function, just resolve all uninstanted type @@ -2152,34 +2148,33 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for ty in &self.unsolved_variables() { let resolved = self.resolve_type_vars_if_possible(ty); - if self.type_var_diverges(resolved) { - debug!("default_type_parameters: defaulting `{:?}` to `!` because it diverges", - resolved); - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, - self.tcx.mk_diverging_default()); - } else { - match self.type_is_unconstrained_numeric(resolved) { - UnconstrainedInt => { - debug!("default_type_parameters: defaulting `{:?}` to `i32`", - resolved); - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.types.i32) - }, - UnconstrainedFloat => { - debug!("default_type_parameters: defaulting `{:?}` to `f32`", - resolved); - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.types.f64) - } - Neither => { } - } + if resolved.is_ty_infer() { + self.apply_diverging_fallback_to_type(ty); + self.apply_numeric_fallback_to_type(ty); } } } - // Implements type inference fallback algorithm - fn select_all_obligations_and_apply_defaults(&self) { - self.select_obligations_where_possible(); - self.default_type_parameters(); - self.select_obligations_where_possible(); + fn apply_diverging_fallback_to_type(&self, ty: Ty<'tcx>) { + assert!(ty.is_ty_infer()); + if self.type_var_diverges(ty) { + debug!("default_type_parameters: defaulting `{:?}` to `!` because it diverges", ty); + self.demand_eqtype(syntax_pos::DUMMY_SP, ty, self.tcx.mk_diverging_default()); + } + } + + fn apply_numeric_fallback_to_type(&self, ty: Ty<'tcx>) { + use rustc::ty::error::UnconstrainedNumeric::Neither; + use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; + + assert!(ty.is_ty_infer()); + let fallback = match self.type_is_unconstrained_numeric(ty) { + UnconstrainedInt => self.tcx.types.i32, + UnconstrainedFloat => self.tcx.types.f64, + Neither => return, + }; + debug!("default_type_parameters: defaulting `{:?}` to `{:?}`", ty, fallback); + self.demand_eqtype(syntax_pos::DUMMY_SP, ty, fallback); } fn select_all_obligations_or_error(&self) { @@ -2189,7 +2184,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // resolutions are handled by now. assert!(self.deferred_call_resolutions.borrow().is_empty()); - self.select_all_obligations_and_apply_defaults(); + self.select_obligations_where_possible(); + self.default_type_parameters(); let mut fulfillment_cx = self.fulfillment_cx.borrow_mut(); @@ -4954,21 +4950,51 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }); } - // Resolves `typ` by a single level if `typ` is a type variable. If no - // resolution is possible, then an error is reported. + // Resolves `typ` by a single level if `typ` is a type variable. + // If no resolution is possible, then an error is reported. + // Numeric inference variables may be left unresolved. pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { let mut ty = self.resolve_type_vars_with_obligations(ty); - if ty.is_ty_var() { - // If not, error. - if !self.is_tainted_by_errors() { - type_error_struct!(self.tcx.sess, sp, ty, E0619, - "the type of this value must be known in this context") - .emit(); + if !ty.is_ty_var() { + ty + } else { + // Try divering fallback. + self.apply_diverging_fallback_to_type(ty); + ty = self.resolve_type_vars_with_obligations(ty); + if !ty.is_ty_var() { + ty + } else { // Fallback failed, error. + self.must_be_known_in_context(sp, ty) } - self.demand_suptype(sp, self.tcx.types.err, ty); - ty = self.tcx.types.err; } - ty + } + + // Same as `structurally_resolved_type` but also resolves numeric vars, with fallback. + pub fn resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + let mut ty = self.resolve_type_vars_with_obligations(ty); + if !ty.is_ty_infer() { + return ty; + } else { + // Try diverging or numeric fallback. + self.apply_diverging_fallback_to_type(ty); + self.apply_numeric_fallback_to_type(ty); + ty = self.resolve_type_vars_with_obligations(ty); + if !ty.is_ty_infer() { + ty + } else { // Fallback failed, error. + self.must_be_known_in_context(sp, ty) + } + } + } + + fn must_be_known_in_context(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + if !self.is_tainted_by_errors() { + type_error_struct!(self.tcx.sess, sp, ty, E0619, + "the type of this value must be known in this context") + .emit(); + } + self.demand_suptype(sp, self.tcx.types.err, ty); + self.tcx.types.err } fn with_breakable_ctxt R, R>(&self, id: ast::NodeId, diff --git a/src/test/compile-fail/derived-errors/issue-31997.rs b/src/test/compile-fail/derived-errors/issue-31997.rs index 2e1d3c55a8f..0385e3b8365 100644 --- a/src/test/compile-fail/derived-errors/issue-31997.rs +++ b/src/test/compile-fail/derived-errors/issue-31997.rs @@ -20,7 +20,9 @@ fn closure(x: F) -> Result } fn foo() -> Result<(), ()> { - try!(closure(|| bar(0 as *mut _))); //~ ERROR cannot find function `bar` in this scope + try!(closure(|| bar(0 as *mut _))); + //~^ ERROR cannot find function `bar` in this scope + //~^^ ERROR cannot cast to a pointer of an unknown kind Ok(()) } diff --git a/src/test/ui/interior-mutability/interior-mutability.stderr b/src/test/ui/interior-mutability/interior-mutability.stderr index f4beb44b82d..dca9ab1b541 100644 --- a/src/test/ui/interior-mutability/interior-mutability.stderr +++ b/src/test/ui/interior-mutability/interior-mutability.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `std::cell::UnsafeCell: std::panic::RefUnwindSafe` is not satisfied in `std::cell::Cell` +error[E0277]: the trait bound `std::cell::UnsafeCell<{integer}>: std::panic::RefUnwindSafe` is not satisfied in `std::cell::Cell<{integer}>` --> $DIR/interior-mutability.rs:15:5 | 15 | catch_unwind(|| { x.set(23); }); //~ ERROR the trait bound - | ^^^^^^^^^^^^ the type std::cell::UnsafeCell may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary + | ^^^^^^^^^^^^ the type std::cell::UnsafeCell<{integer}> may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `std::cell::Cell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` - = note: required because it appears within the type `std::cell::Cell` - = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&std::cell::Cell` - = note: required because it appears within the type `[closure@$DIR/interior-mutability.rs:15:18: 15:35 x:&std::cell::Cell]` + = help: within `std::cell::Cell<{integer}>`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell<{integer}>` + = note: required because it appears within the type `std::cell::Cell<{integer}>` + = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&std::cell::Cell<{integer}>` + = note: required because it appears within the type `[closure@$DIR/interior-mutability.rs:15:18: 15:35 x:&std::cell::Cell<{integer}>]` = note: required by `std::panic::catch_unwind` error: aborting due to previous error diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr index 5d25cb2f93c..1b056486ad9 100644 --- a/src/test/ui/mismatched_types/issue-26480.stderr +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -7,7 +7,7 @@ error[E0308]: mismatched types 37 | write!(hello); | -------------- in this macro invocation -error[E0605]: non-primitive cast: `{integer}` as `()` +error[E0605]: non-primitive cast: `i32` as `()` --> $DIR/issue-26480.rs:32:19 | 32 | ($x:expr) => ($x as ()) //~ ERROR non-primitive cast From f3cd4a7f64c50ff5935f4d507ae1103c93b8a2ad Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Wed, 13 Dec 2017 13:56:57 -0200 Subject: [PATCH 3/9] Refactor away `fn default_type_parameters` It had only one caller. --- src/librustc_typeck/check/mod.rs | 46 ++++++++++++-------------------- 1 file changed, 17 insertions(+), 29 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index aff96e39cfc..666b8e06522 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2127,34 +2127,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - /// Apply "fallbacks" to some types - /// unconstrained types get replaced with ! or () (depending on whether - /// feature(never_type) is enabled), unconstrained ints with i32, and - /// unconstrained floats with f64. - fn default_type_parameters(&self) { - // Defaulting inference variables becomes very dubious if we have - // encountered type-checking errors. Therefore, if we think we saw - // some errors in this function, just resolve all uninstanted type - // varibles to TyError. - if self.is_tainted_by_errors() { - for ty in &self.unsolved_variables() { - if let ty::TyInfer(_) = self.shallow_resolve(ty).sty { - debug!("default_type_parameters: defaulting `{:?}` to error", ty); - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx().types.err); - } - } - return; - } - - for ty in &self.unsolved_variables() { - let resolved = self.resolve_type_vars_if_possible(ty); - if resolved.is_ty_infer() { - self.apply_diverging_fallback_to_type(ty); - self.apply_numeric_fallback_to_type(ty); - } - } - } - fn apply_diverging_fallback_to_type(&self, ty: Ty<'tcx>) { assert!(ty.is_ty_infer()); if self.type_var_diverges(ty) { @@ -2185,7 +2157,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { assert!(self.deferred_call_resolutions.borrow().is_empty()); self.select_obligations_where_possible(); - self.default_type_parameters(); + + // Apply fallbacks to unsolved variables. + // Non-numerics get replaced with ! or () (depending on whether + // feature(never_type) is enabled), unconstrained ints with i32, + // unconstrained floats with f64. + for ty in &self.unsolved_variables() { + if self.is_tainted_by_errors() { + // Defaulting inference variables becomes very dubious if we have + // encountered type-checking errors. In that case, + // just resolve all uninstanted type variables to TyError. + debug!("default_type_parameters: defaulting `{:?}` to error", ty); + self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx().types.err); + } else { + self.apply_diverging_fallback_to_type(ty); + self.apply_numeric_fallback_to_type(ty); + } + } let mut fulfillment_cx = self.fulfillment_cx.borrow_mut(); From 02084f3304acfa68e79d213a5ebd1c3478680741 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Mon, 18 Dec 2017 17:31:23 -0200 Subject: [PATCH 4/9] No fallback in `structurally_resolve_types`. Further refactoring. Put all fallback in `apply_fallback_if_possible`. --- src/librustc_typeck/check/cast.rs | 2 +- src/librustc_typeck/check/mod.rs | 50 ++++++------------- .../{issue-26480.rs => issue-26480-1.rs} | 6 +-- .../ui/mismatched_types/issue-26480-1.stderr | 11 ++++ src/test/ui/mismatched_types/issue-26480-2.rs | 18 +++++++ .../ui/mismatched_types/issue-26480-2.stderr | 13 +++++ .../ui/mismatched_types/issue-26480.stderr | 13 +---- 7 files changed, 59 insertions(+), 54 deletions(-) rename src/test/ui/mismatched_types/{issue-26480.rs => issue-26480-1.rs} (91%) create mode 100644 src/test/ui/mismatched_types/issue-26480-1.stderr create mode 100644 src/test/ui/mismatched_types/issue-26480-2.rs create mode 100644 src/test/ui/mismatched_types/issue-26480-2.stderr diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index bc157d6feea..631f7a740c4 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -393,7 +393,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { pub fn check(mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) { self.expr_ty = fcx.resolved_type(self.span, self.expr_ty); - self.cast_ty = fcx.resolved_type(self.span, self.cast_ty); + self.cast_ty = fcx.structurally_resolved_type(self.span, self.cast_ty); debug!("check_cast({}, {:?} as {:?})", self.expr.id, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 666b8e06522..610510c5c74 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2127,23 +2127,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - fn apply_diverging_fallback_to_type(&self, ty: Ty<'tcx>) { - assert!(ty.is_ty_infer()); - if self.type_var_diverges(ty) { - debug!("default_type_parameters: defaulting `{:?}` to `!` because it diverges", ty); - self.demand_eqtype(syntax_pos::DUMMY_SP, ty, self.tcx.mk_diverging_default()); - } - } - - fn apply_numeric_fallback_to_type(&self, ty: Ty<'tcx>) { + // Tries to apply a fallback to `ty` if it is an unsolved variable. + // Non-numerics get replaced with ! or () (depending on whether + // feature(never_type) is enabled), unconstrained ints with i32, + // unconstrained floats with f64. + // Defaulting inference variables becomes very dubious if we have + // encountered type-checking errors. In that case, fallback to TyError. + fn apply_fallback_if_possible(&self, ty: Ty<'tcx>) { use rustc::ty::error::UnconstrainedNumeric::Neither; use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; assert!(ty.is_ty_infer()); let fallback = match self.type_is_unconstrained_numeric(ty) { + _ if self.is_tainted_by_errors() => self.tcx().types.err, UnconstrainedInt => self.tcx.types.i32, UnconstrainedFloat => self.tcx.types.f64, - Neither => return, + Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(), + Neither => return }; debug!("default_type_parameters: defaulting `{:?}` to `{:?}`", ty, fallback); self.demand_eqtype(syntax_pos::DUMMY_SP, ty, fallback); @@ -2158,21 +2158,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.select_obligations_where_possible(); - // Apply fallbacks to unsolved variables. - // Non-numerics get replaced with ! or () (depending on whether - // feature(never_type) is enabled), unconstrained ints with i32, - // unconstrained floats with f64. for ty in &self.unsolved_variables() { - if self.is_tainted_by_errors() { - // Defaulting inference variables becomes very dubious if we have - // encountered type-checking errors. In that case, - // just resolve all uninstanted type variables to TyError. - debug!("default_type_parameters: defaulting `{:?}` to error", ty); - self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx().types.err); - } else { - self.apply_diverging_fallback_to_type(ty); - self.apply_numeric_fallback_to_type(ty); - } + self.apply_fallback_if_possible(ty); } let mut fulfillment_cx = self.fulfillment_cx.borrow_mut(); @@ -4942,18 +4929,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // If no resolution is possible, then an error is reported. // Numeric inference variables may be left unresolved. pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - let mut ty = self.resolve_type_vars_with_obligations(ty); + let ty = self.resolve_type_vars_with_obligations(ty); if !ty.is_ty_var() { ty } else { - // Try divering fallback. - self.apply_diverging_fallback_to_type(ty); - ty = self.resolve_type_vars_with_obligations(ty); - if !ty.is_ty_var() { - ty - } else { // Fallback failed, error. - self.must_be_known_in_context(sp, ty) - } + self.must_be_known_in_context(sp, ty) } } @@ -4963,9 +4943,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if !ty.is_ty_infer() { return ty; } else { - // Try diverging or numeric fallback. - self.apply_diverging_fallback_to_type(ty); - self.apply_numeric_fallback_to_type(ty); + self.apply_fallback_if_possible(ty); ty = self.resolve_type_vars_with_obligations(ty); if !ty.is_ty_infer() { ty diff --git a/src/test/ui/mismatched_types/issue-26480.rs b/src/test/ui/mismatched_types/issue-26480-1.rs similarity index 91% rename from src/test/ui/mismatched_types/issue-26480.rs rename to src/test/ui/mismatched_types/issue-26480-1.rs index 33c5e74fafa..36a30ccb0fc 100644 --- a/src/test/ui/mismatched_types/issue-26480.rs +++ b/src/test/ui/mismatched_types/issue-26480-1.rs @@ -7,6 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: --error-format=human extern { fn write(fildes: i32, buf: *const i8, nbyte: u64) -> i64; @@ -28,12 +29,7 @@ macro_rules! write { }} } -macro_rules! cast { - ($x:expr) => ($x as ()) //~ ERROR non-primitive cast -} - fn main() { let hello = ['H', 'e', 'y']; write!(hello); - cast!(2); } diff --git a/src/test/ui/mismatched_types/issue-26480-1.stderr b/src/test/ui/mismatched_types/issue-26480-1.stderr new file mode 100644 index 00000000000..326b427b0fb --- /dev/null +++ b/src/test/ui/mismatched_types/issue-26480-1.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/issue-26480-1.rs:27:19 + | +27 | $arr.len() * size_of($arr[0])); //~ ERROR mismatched types + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u64, found usize +... +34 | write!(hello); + | -------------- in this macro invocation + +error: aborting due to previous error + diff --git a/src/test/ui/mismatched_types/issue-26480-2.rs b/src/test/ui/mismatched_types/issue-26480-2.rs new file mode 100644 index 00000000000..7015e5909e9 --- /dev/null +++ b/src/test/ui/mismatched_types/issue-26480-2.rs @@ -0,0 +1,18 @@ +// Copyright 2016 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-flags: --error-format=human + +macro_rules! cast { + ($x:expr) => ($x as ()) //~ ERROR non-primitive cast +} + +fn main() { + cast!(2); +} diff --git a/src/test/ui/mismatched_types/issue-26480-2.stderr b/src/test/ui/mismatched_types/issue-26480-2.stderr new file mode 100644 index 00000000000..3f6dcccdedb --- /dev/null +++ b/src/test/ui/mismatched_types/issue-26480-2.stderr @@ -0,0 +1,13 @@ +error[E0605]: non-primitive cast: `i32` as `()` + --> $DIR/issue-26480-2.rs:13:19 + | +13 | ($x:expr) => ($x as ()) //~ ERROR non-primitive cast + | ^^^^^^^^ +... +17 | cast!(2); + | --------- in this macro invocation + | + = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + +error: aborting due to previous error + diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr index 1b056486ad9..27698c864c3 100644 --- a/src/test/ui/mismatched_types/issue-26480.stderr +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -7,16 +7,5 @@ error[E0308]: mismatched types 37 | write!(hello); | -------------- in this macro invocation -error[E0605]: non-primitive cast: `i32` as `()` - --> $DIR/issue-26480.rs:32:19 - | -32 | ($x:expr) => ($x as ()) //~ ERROR non-primitive cast - | ^^^^^^^^ -... -38 | cast!(2); - | --------- in this macro invocation - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait - -error: aborting due to 2 previous errors +error: aborting due to previous error From 4c0ff95e6ecd861741e868cc729afe0339a4b8c7 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Thu, 21 Dec 2017 07:40:54 -0200 Subject: [PATCH 5/9] Be more explicit about how and why we need fallback in targets of casts --- src/librustc_typeck/check/cast.rs | 10 +++++++-- src/librustc_typeck/check/mod.rs | 29 +++++++++---------------- src/test/run-pass/cast-does-fallback.rs | 16 ++++++++++++++ 3 files changed, 34 insertions(+), 21 deletions(-) create mode 100644 src/test/run-pass/cast-does-fallback.rs diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 631f7a740c4..8dde3d7ab98 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -38,7 +38,7 @@ //! expression, `e as U2` is not necessarily so (in fact it will only be valid if //! `U1` coerces to `U2`). -use super::{Diverges, FnCtxt}; +use super::{Diverges, Fallback, FnCtxt}; use errors::DiagnosticBuilder; use hir::def_id::DefId; @@ -392,7 +392,13 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } pub fn check(mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) { - self.expr_ty = fcx.resolved_type(self.span, self.expr_ty); + self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty); + // For backwards compatibility we apply numeric fallback here. This means that in: + // `let x = 100; x as u8;`, we infer `x` to `i32` rather than `u8`. + if self.expr_ty.is_ty_infer() { + fcx.apply_fallback_if_possible(self.expr_ty, Fallback::Numeric); + self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty); + } self.cast_ty = fcx.structurally_resolved_type(self.span, self.cast_ty); debug!("check_cast({}, {:?} as {:?})", diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 610510c5c74..e97de581173 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1724,6 +1724,12 @@ enum TupleArgumentsFlag { TupleArguments, } +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Fallback { + Full, + Numeric +} + impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -2133,7 +2139,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // unconstrained floats with f64. // Defaulting inference variables becomes very dubious if we have // encountered type-checking errors. In that case, fallback to TyError. - fn apply_fallback_if_possible(&self, ty: Ty<'tcx>) { + fn apply_fallback_if_possible(&self, ty: Ty<'tcx>, fallback: Fallback) { use rustc::ty::error::UnconstrainedNumeric::Neither; use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; @@ -2142,7 +2148,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ if self.is_tainted_by_errors() => self.tcx().types.err, UnconstrainedInt => self.tcx.types.i32, UnconstrainedFloat => self.tcx.types.f64, - Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(), + Neither if self.type_var_diverges(ty) && fallback == Fallback::Full + => self.tcx.mk_diverging_default(), Neither => return }; debug!("default_type_parameters: defaulting `{:?}` to `{:?}`", ty, fallback); @@ -2159,7 +2166,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.select_obligations_where_possible(); for ty in &self.unsolved_variables() { - self.apply_fallback_if_possible(ty); + self.apply_fallback_if_possible(ty, Fallback::Full); } let mut fulfillment_cx = self.fulfillment_cx.borrow_mut(); @@ -4937,22 +4944,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - // Same as `structurally_resolved_type` but also resolves numeric vars, with fallback. - pub fn resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - let mut ty = self.resolve_type_vars_with_obligations(ty); - if !ty.is_ty_infer() { - return ty; - } else { - self.apply_fallback_if_possible(ty); - ty = self.resolve_type_vars_with_obligations(ty); - if !ty.is_ty_infer() { - ty - } else { // Fallback failed, error. - self.must_be_known_in_context(sp, ty) - } - } - } - fn must_be_known_in_context(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { if !self.is_tainted_by_errors() { type_error_struct!(self.tcx.sess, sp, ty, E0619, diff --git a/src/test/run-pass/cast-does-fallback.rs b/src/test/run-pass/cast-does-fallback.rs new file mode 100644 index 00000000000..86d6e387b25 --- /dev/null +++ b/src/test/run-pass/cast-does-fallback.rs @@ -0,0 +1,16 @@ +// Copyright 2017 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. + +pub fn main() { + let cap = 512 * 512; + cap as u8; + // Assert `cap` did not get inferred to `u8` and overflowed. + assert_ne!(cap, 0); +} From cd4de4cece143e8dbaeeff93492afcbb356d3051 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Thu, 18 Jan 2018 10:38:33 -0200 Subject: [PATCH 6/9] Suppress unknown cast errors in the presence of other errors. --- src/librustc_typeck/check/cast.rs | 3 +++ src/librustc_typeck/check/mod.rs | 8 ++++++-- .../compile-fail/derived-errors/issue-31997.rs | 4 +--- src/test/ui/issue-45730.rs | 4 ++++ src/test/ui/issue-45730.stderr | 8 ++++---- .../ui/mismatched_types/issue-26480-1.stderr | 11 ----------- src/test/ui/mismatched_types/issue-26480-2.rs | 18 ------------------ .../ui/mismatched_types/issue-26480-2.stderr | 13 ------------- .../{issue-26480-1.rs => issue-26480.rs} | 6 +++++- .../ui/mismatched_types/issue-26480.stderr | 13 ++++++++++++- 10 files changed, 35 insertions(+), 53 deletions(-) delete mode 100644 src/test/ui/mismatched_types/issue-26480-1.stderr delete mode 100644 src/test/ui/mismatched_types/issue-26480-2.rs delete mode 100644 src/test/ui/mismatched_types/issue-26480-2.stderr rename src/test/ui/mismatched_types/{issue-26480-1.rs => issue-26480.rs} (91%) diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 8dde3d7ab98..2978921fc62 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -290,6 +290,9 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } CastError::UnknownCastPtrKind | CastError::UnknownExprPtrKind => { + if fcx.is_tainted_by_errors() { + return; + } let unknown_cast_to = match e { CastError::UnknownCastPtrKind => true, CastError::UnknownExprPtrKind => false, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e97de581173..57e40ec19af 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2148,8 +2148,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ if self.is_tainted_by_errors() => self.tcx().types.err, UnconstrainedInt => self.tcx.types.i32, UnconstrainedFloat => self.tcx.types.f64, - Neither if self.type_var_diverges(ty) && fallback == Fallback::Full - => self.tcx.mk_diverging_default(), + Neither if self.type_var_diverges(ty) => { + match fallback { + Fallback::Full => self.tcx.mk_diverging_default(), + Fallback::Numeric => return, + } + } Neither => return }; debug!("default_type_parameters: defaulting `{:?}` to `{:?}`", ty, fallback); diff --git a/src/test/compile-fail/derived-errors/issue-31997.rs b/src/test/compile-fail/derived-errors/issue-31997.rs index 0385e3b8365..2e1d3c55a8f 100644 --- a/src/test/compile-fail/derived-errors/issue-31997.rs +++ b/src/test/compile-fail/derived-errors/issue-31997.rs @@ -20,9 +20,7 @@ fn closure(x: F) -> Result } fn foo() -> Result<(), ()> { - try!(closure(|| bar(0 as *mut _))); - //~^ ERROR cannot find function `bar` in this scope - //~^^ ERROR cannot cast to a pointer of an unknown kind + try!(closure(|| bar(0 as *mut _))); //~ ERROR cannot find function `bar` in this scope Ok(()) } diff --git a/src/test/ui/issue-45730.rs b/src/test/ui/issue-45730.rs index d733c8e6de2..1fe0b1ae2d2 100644 --- a/src/test/ui/issue-45730.rs +++ b/src/test/ui/issue-45730.rs @@ -11,9 +11,13 @@ use std::fmt; fn main() { let x: *const _ = 0 as _; //~ ERROR cannot cast +} +fn a() { let x: *const _ = 0 as *const _; //~ ERROR cannot cast let y: Option<*const fmt::Debug> = Some(x) as _; +} +fn c() { let x = 0 as *const i32 as *const _ as *mut _; //~ ERROR cannot cast } diff --git a/src/test/ui/issue-45730.stderr b/src/test/ui/issue-45730.stderr index 94d39239117..13205eead43 100644 --- a/src/test/ui/issue-45730.stderr +++ b/src/test/ui/issue-45730.stderr @@ -9,9 +9,9 @@ error[E0641]: cannot cast to a pointer of an unknown kind = note: The type information given here is insufficient to check whether the pointer cast is valid error[E0641]: cannot cast to a pointer of an unknown kind - --> $DIR/issue-45730.rs:15:23 + --> $DIR/issue-45730.rs:17:23 | -15 | let x: *const _ = 0 as *const _; //~ ERROR cannot cast +17 | let x: *const _ = 0 as *const _; //~ ERROR cannot cast | ^^^^^-------- | | | help: consider giving more type information @@ -19,9 +19,9 @@ error[E0641]: cannot cast to a pointer of an unknown kind = note: The type information given here is insufficient to check whether the pointer cast is valid error[E0641]: cannot cast to a pointer of an unknown kind - --> $DIR/issue-45730.rs:18:13 + --> $DIR/issue-45730.rs:22:13 | -18 | let x = 0 as *const i32 as *const _ as *mut _; //~ ERROR cannot cast +22 | let x = 0 as *const i32 as *const _ as *mut _; //~ ERROR cannot cast | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------ | | | help: consider giving more type information diff --git a/src/test/ui/mismatched_types/issue-26480-1.stderr b/src/test/ui/mismatched_types/issue-26480-1.stderr deleted file mode 100644 index 326b427b0fb..00000000000 --- a/src/test/ui/mismatched_types/issue-26480-1.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/issue-26480-1.rs:27:19 - | -27 | $arr.len() * size_of($arr[0])); //~ ERROR mismatched types - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u64, found usize -... -34 | write!(hello); - | -------------- in this macro invocation - -error: aborting due to previous error - diff --git a/src/test/ui/mismatched_types/issue-26480-2.rs b/src/test/ui/mismatched_types/issue-26480-2.rs deleted file mode 100644 index 7015e5909e9..00000000000 --- a/src/test/ui/mismatched_types/issue-26480-2.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2016 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-flags: --error-format=human - -macro_rules! cast { - ($x:expr) => ($x as ()) //~ ERROR non-primitive cast -} - -fn main() { - cast!(2); -} diff --git a/src/test/ui/mismatched_types/issue-26480-2.stderr b/src/test/ui/mismatched_types/issue-26480-2.stderr deleted file mode 100644 index 3f6dcccdedb..00000000000 --- a/src/test/ui/mismatched_types/issue-26480-2.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0605]: non-primitive cast: `i32` as `()` - --> $DIR/issue-26480-2.rs:13:19 - | -13 | ($x:expr) => ($x as ()) //~ ERROR non-primitive cast - | ^^^^^^^^ -... -17 | cast!(2); - | --------- in this macro invocation - | - = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait - -error: aborting due to previous error - diff --git a/src/test/ui/mismatched_types/issue-26480-1.rs b/src/test/ui/mismatched_types/issue-26480.rs similarity index 91% rename from src/test/ui/mismatched_types/issue-26480-1.rs rename to src/test/ui/mismatched_types/issue-26480.rs index 36a30ccb0fc..33c5e74fafa 100644 --- a/src/test/ui/mismatched_types/issue-26480-1.rs +++ b/src/test/ui/mismatched_types/issue-26480.rs @@ -7,7 +7,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: --error-format=human extern { fn write(fildes: i32, buf: *const i8, nbyte: u64) -> i64; @@ -29,7 +28,12 @@ macro_rules! write { }} } +macro_rules! cast { + ($x:expr) => ($x as ()) //~ ERROR non-primitive cast +} + fn main() { let hello = ['H', 'e', 'y']; write!(hello); + cast!(2); } diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr index 27698c864c3..5d25cb2f93c 100644 --- a/src/test/ui/mismatched_types/issue-26480.stderr +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -7,5 +7,16 @@ error[E0308]: mismatched types 37 | write!(hello); | -------------- in this macro invocation -error: aborting due to previous error +error[E0605]: non-primitive cast: `{integer}` as `()` + --> $DIR/issue-26480.rs:32:19 + | +32 | ($x:expr) => ($x as ()) //~ ERROR non-primitive cast + | ^^^^^^^^ +... +38 | cast!(2); + | --------- in this macro invocation + | + = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait + +error: aborting due to 2 previous errors From f8c140465f20217913f14b7423f7110d0cc7b57c Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Sat, 27 Jan 2018 15:42:23 -0200 Subject: [PATCH 7/9] Only closure analysis should run after fallback. Move `check_casts` and `resolve_generator_interiors` to before fallback. Rename `apply_fallback_if_possible` to `fallback_if_possible`. Refactor `select_all_obligations_or_error`. --- src/librustc_typeck/check/cast.rs | 2 +- src/librustc_typeck/check/mod.rs | 38 +++++++++---------- .../interior-mutability.stderr | 12 +++--- 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 2978921fc62..dae5ba14bfb 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -399,7 +399,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { // For backwards compatibility we apply numeric fallback here. This means that in: // `let x = 100; x as u8;`, we infer `x` to `i32` rather than `u8`. if self.expr_ty.is_ty_infer() { - fcx.apply_fallback_if_possible(self.expr_ty, Fallback::Numeric); + fcx.fallback_if_possible(self.expr_ty, Fallback::Numeric); self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty); } self.cast_ty = fcx.structurally_resolved_type(self.span, self.cast_ty); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 57e40ec19af..b1645ed9228 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -858,9 +858,19 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fcx }; - fcx.select_obligations_where_possible(); - fcx.closure_analyze(body); fcx.check_casts(); + + // All type checking constraints were added, try to fallback unsolved variables. + fcx.select_obligations_where_possible(); + for ty in &fcx.unsolved_variables() { + fcx.fallback_if_possible(ty, Fallback::Full); + } + fcx.select_obligations_where_possible(); + + // Closure and generater analysis may run after fallback + // because they doen't constrain other type variables. + fcx.closure_analyze(body); + assert!(fcx.deferred_call_resolutions.borrow().is_empty()); fcx.resolve_generator_interiors(def_id); fcx.select_all_obligations_or_error(); @@ -2137,9 +2147,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Non-numerics get replaced with ! or () (depending on whether // feature(never_type) is enabled), unconstrained ints with i32, // unconstrained floats with f64. - // Defaulting inference variables becomes very dubious if we have - // encountered type-checking errors. In that case, fallback to TyError. - fn apply_fallback_if_possible(&self, ty: Ty<'tcx>, fallback: Fallback) { + // Fallback becomes very dubious if we have encountered type-checking errors. + // In that case, fallback to TyError. + fn fallback_if_possible(&self, ty: Ty<'tcx>, fallback: Fallback) { use rustc::ty::error::UnconstrainedNumeric::Neither; use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; @@ -2162,22 +2172,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn select_all_obligations_or_error(&self) { debug!("select_all_obligations_or_error"); - - // upvar inference should have ensured that all deferred call - // resolutions are handled by now. - assert!(self.deferred_call_resolutions.borrow().is_empty()); - - self.select_obligations_where_possible(); - - for ty in &self.unsolved_variables() { - self.apply_fallback_if_possible(ty, Fallback::Full); - } - - let mut fulfillment_cx = self.fulfillment_cx.borrow_mut(); - - match fulfillment_cx.select_all_or_error(self) { - Ok(()) => { } - Err(errors) => { self.report_fulfillment_errors(&errors, self.inh.body_id); } + if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) { + self.report_fulfillment_errors(&errors, self.inh.body_id); } } diff --git a/src/test/ui/interior-mutability/interior-mutability.stderr b/src/test/ui/interior-mutability/interior-mutability.stderr index dca9ab1b541..f4beb44b82d 100644 --- a/src/test/ui/interior-mutability/interior-mutability.stderr +++ b/src/test/ui/interior-mutability/interior-mutability.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `std::cell::UnsafeCell<{integer}>: std::panic::RefUnwindSafe` is not satisfied in `std::cell::Cell<{integer}>` +error[E0277]: the trait bound `std::cell::UnsafeCell: std::panic::RefUnwindSafe` is not satisfied in `std::cell::Cell` --> $DIR/interior-mutability.rs:15:5 | 15 | catch_unwind(|| { x.set(23); }); //~ ERROR the trait bound - | ^^^^^^^^^^^^ the type std::cell::UnsafeCell<{integer}> may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary + | ^^^^^^^^^^^^ the type std::cell::UnsafeCell may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `std::cell::Cell<{integer}>`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell<{integer}>` - = note: required because it appears within the type `std::cell::Cell<{integer}>` - = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&std::cell::Cell<{integer}>` - = note: required because it appears within the type `[closure@$DIR/interior-mutability.rs:15:18: 15:35 x:&std::cell::Cell<{integer}>]` + = help: within `std::cell::Cell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` + = note: required because it appears within the type `std::cell::Cell` + = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&std::cell::Cell` + = note: required because it appears within the type `[closure@$DIR/interior-mutability.rs:15:18: 15:35 x:&std::cell::Cell]` = note: required by `std::panic::catch_unwind` error: aborting due to previous error From b813718f6dff49b851fcd18a5674640554bda2e5 Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Sat, 27 Jan 2018 18:17:44 -0200 Subject: [PATCH 8/9] Refactor away `fn must_be_known_in_context` --- src/librustc_typeck/check/mod.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b1645ed9228..0395b3eb4aa 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4940,20 +4940,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if !ty.is_ty_var() { ty } else { - self.must_be_known_in_context(sp, ty) + if !self.is_tainted_by_errors() { + type_error_struct!(self.tcx.sess, sp, ty, E0619, + "the type of this value must be known in this context") + .emit(); + } + self.demand_suptype(sp, self.tcx.types.err, ty); + self.tcx.types.err } } - fn must_be_known_in_context(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - if !self.is_tainted_by_errors() { - type_error_struct!(self.tcx.sess, sp, ty, E0619, - "the type of this value must be known in this context") - .emit(); - } - self.demand_suptype(sp, self.tcx.types.err, ty); - self.tcx.types.err - } - fn with_breakable_ctxt R, R>(&self, id: ast::NodeId, ctxt: BreakableCtxt<'gcx, 'tcx>, f: F) -> (BreakableCtxt<'gcx, 'tcx>, R) { From d49d428f791b97c476c066deb9c2b3c20165199f Mon Sep 17 00:00:00 2001 From: "leonardo.yvens" Date: Thu, 8 Feb 2018 17:36:17 -0200 Subject: [PATCH 9/9] Revert checking casts before fallback. This turns out to not be backwards compatible. --- src/librustc_typeck/check/cast.rs | 11 +---------- src/librustc_typeck/check/mod.rs | 25 ++++++++----------------- src/test/run-pass/cast-does-fallback.rs | 4 ++++ src/test/ui/issue-45730.rs | 4 ---- src/test/ui/issue-45730.stderr | 8 ++++---- 5 files changed, 17 insertions(+), 35 deletions(-) diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index dae5ba14bfb..48bd7b14fc9 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -38,7 +38,7 @@ //! expression, `e as U2` is not necessarily so (in fact it will only be valid if //! `U1` coerces to `U2`). -use super::{Diverges, Fallback, FnCtxt}; +use super::{Diverges, FnCtxt}; use errors::DiagnosticBuilder; use hir::def_id::DefId; @@ -290,9 +290,6 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { } CastError::UnknownCastPtrKind | CastError::UnknownExprPtrKind => { - if fcx.is_tainted_by_errors() { - return; - } let unknown_cast_to = match e { CastError::UnknownCastPtrKind => true, CastError::UnknownExprPtrKind => false, @@ -396,12 +393,6 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { pub fn check(mut self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) { self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty); - // For backwards compatibility we apply numeric fallback here. This means that in: - // `let x = 100; x as u8;`, we infer `x` to `i32` rather than `u8`. - if self.expr_ty.is_ty_infer() { - fcx.fallback_if_possible(self.expr_ty, Fallback::Numeric); - self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty); - } self.cast_ty = fcx.structurally_resolved_type(self.span, self.cast_ty); debug!("check_cast({}, {:?} as {:?})", diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0395b3eb4aa..f50bd03a9e0 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -858,17 +858,19 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fcx }; - fcx.check_casts(); - // All type checking constraints were added, try to fallback unsolved variables. fcx.select_obligations_where_possible(); for ty in &fcx.unsolved_variables() { - fcx.fallback_if_possible(ty, Fallback::Full); + fcx.fallback_if_possible(ty); } fcx.select_obligations_where_possible(); + // Even though coercion casts provide type hints, we check casts after fallback for + // backwards compatibility. This makes fallback a stronger type hint than a cast coercion. + fcx.check_casts(); + // Closure and generater analysis may run after fallback - // because they doen't constrain other type variables. + // because they don't constrain other type variables. fcx.closure_analyze(body); assert!(fcx.deferred_call_resolutions.borrow().is_empty()); fcx.resolve_generator_interiors(def_id); @@ -1734,12 +1736,6 @@ enum TupleArgumentsFlag { TupleArguments, } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Fallback { - Full, - Numeric -} - impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -2149,7 +2145,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // unconstrained floats with f64. // Fallback becomes very dubious if we have encountered type-checking errors. // In that case, fallback to TyError. - fn fallback_if_possible(&self, ty: Ty<'tcx>, fallback: Fallback) { + fn fallback_if_possible(&self, ty: Ty<'tcx>) { use rustc::ty::error::UnconstrainedNumeric::Neither; use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat}; @@ -2158,12 +2154,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ if self.is_tainted_by_errors() => self.tcx().types.err, UnconstrainedInt => self.tcx.types.i32, UnconstrainedFloat => self.tcx.types.f64, - Neither if self.type_var_diverges(ty) => { - match fallback { - Fallback::Full => self.tcx.mk_diverging_default(), - Fallback::Numeric => return, - } - } + Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(), Neither => return }; debug!("default_type_parameters: defaulting `{:?}` to `{:?}`", ty, fallback); diff --git a/src/test/run-pass/cast-does-fallback.rs b/src/test/run-pass/cast-does-fallback.rs index 86d6e387b25..aa6752ffc35 100644 --- a/src/test/run-pass/cast-does-fallback.rs +++ b/src/test/run-pass/cast-does-fallback.rs @@ -9,6 +9,10 @@ // except according to those terms. pub fn main() { + // Test that these type check correctly. + (&42u8 >> 4) as usize; + (&42u8 << 4) as usize; + let cap = 512 * 512; cap as u8; // Assert `cap` did not get inferred to `u8` and overflowed. diff --git a/src/test/ui/issue-45730.rs b/src/test/ui/issue-45730.rs index 1fe0b1ae2d2..d733c8e6de2 100644 --- a/src/test/ui/issue-45730.rs +++ b/src/test/ui/issue-45730.rs @@ -11,13 +11,9 @@ use std::fmt; fn main() { let x: *const _ = 0 as _; //~ ERROR cannot cast -} -fn a() { let x: *const _ = 0 as *const _; //~ ERROR cannot cast let y: Option<*const fmt::Debug> = Some(x) as _; -} -fn c() { let x = 0 as *const i32 as *const _ as *mut _; //~ ERROR cannot cast } diff --git a/src/test/ui/issue-45730.stderr b/src/test/ui/issue-45730.stderr index 13205eead43..94d39239117 100644 --- a/src/test/ui/issue-45730.stderr +++ b/src/test/ui/issue-45730.stderr @@ -9,9 +9,9 @@ error[E0641]: cannot cast to a pointer of an unknown kind = note: The type information given here is insufficient to check whether the pointer cast is valid error[E0641]: cannot cast to a pointer of an unknown kind - --> $DIR/issue-45730.rs:17:23 + --> $DIR/issue-45730.rs:15:23 | -17 | let x: *const _ = 0 as *const _; //~ ERROR cannot cast +15 | let x: *const _ = 0 as *const _; //~ ERROR cannot cast | ^^^^^-------- | | | help: consider giving more type information @@ -19,9 +19,9 @@ error[E0641]: cannot cast to a pointer of an unknown kind = note: The type information given here is insufficient to check whether the pointer cast is valid error[E0641]: cannot cast to a pointer of an unknown kind - --> $DIR/issue-45730.rs:22:13 + --> $DIR/issue-45730.rs:18:13 | -22 | let x = 0 as *const i32 as *const _ as *mut _; //~ ERROR cannot cast +18 | let x = 0 as *const i32 as *const _ as *mut _; //~ ERROR cannot cast | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------ | | | help: consider giving more type information