Skip to content

Rollup of 11 pull requests #66545

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 39 commits into from
Nov 19, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
71e5018
ci: replace MINGW_URL with CUSTOM_MINGW=1
pietroalbini Oct 30, 2019
53c2c04
ci: remove the MINGW_DIR and MINGW_ARCHIVE env vars
pietroalbini Oct 30, 2019
af6b266
ci: remove the MSYS_BITS env var
pietroalbini Oct 30, 2019
6104aa7
ci: extract validate-toolstate into a script
pietroalbini Oct 30, 2019
d623c56
ci: extract running the build into a script
pietroalbini Oct 30, 2019
e209ee4
ci: extract collecting cpu stats into a script
pietroalbini Oct 30, 2019
c90cc12
ci: move validate-toolstate.sh in the mingw-check image
pietroalbini Oct 31, 2019
14da85c
ci: move mirrors to https://ci-mirrors.rust-lang.org
pietroalbini Nov 4, 2019
85132b2
ci: download curl and openssl from s3 for dist-x86_64-linux
pietroalbini Nov 6, 2019
71cf364
Fix the source code highlighting on source comments
dns2utf8 Nov 15, 2019
1bbb816
Prevent jumps when selecting one or many lines
dns2utf8 Nov 15, 2019
4e1eeb9
Add explanation message for E0641
clemkoh Nov 16, 2019
dc137dd
Update ui tests
clemkoh Nov 16, 2019
0487f0c
Suggest calling async closure when needed
estebank Nov 9, 2019
d7efa5b
review comments
estebank Nov 17, 2019
d8ea786
Add JohnTitor to rustc-guide toolstate notification list
JohnTitor Nov 17, 2019
de122e6
std::error::Chain: remove Copy
haraldh Nov 15, 2019
4610867
Add long error explanation for E0594
GuillaumeGomez Nov 6, 2019
cd13335
Update ui tests
GuillaumeGomez Nov 6, 2019
0e2ccaa
Fix 'type annotations needed' error with opaque types
Aaron1011 Nov 15, 2019
61c75bd
Add explanation of unconstrained opaque type
Aaron1011 Nov 15, 2019
f87177b
Replace bool with new `FallbackMode` enum
Aaron1011 Nov 15, 2019
a11abe0
Update test output
Aaron1011 Nov 15, 2019
614da98
review comments
estebank Nov 17, 2019
f74fe81
resolve: Give derive helpers highest priority during resolution
petrochenkov Nov 18, 2019
c981c99
Move E0594 to new error code system
GuillaumeGomez Nov 18, 2019
f6b327b
Remove compiler_builtins_lib feature from libstd
dingelish Nov 19, 2019
c84fae1
Move the definition of `QueryResult` into `plumbing.rs`.
nnethercote Nov 1, 2019
49077c5
Rollup merge of #66090 - pietroalbini:ci-improvements, r=alexcrichton
Centril Nov 19, 2019
40deec8
Rollup merge of #66155 - GuillaumeGomez:long-err-explanation-E0594, r…
Centril Nov 19, 2019
0b0d683
Rollup merge of #66239 - estebank:suggest-async-closure-call, r=Centril
Centril Nov 19, 2019
95b9766
Rollup merge of #66430 - dns2utf8:fix_code_selection_click_handler, r…
Centril Nov 19, 2019
ee535a0
Rollup merge of #66431 - Aaron1011:fix/opaque-type-infer, r=varkor
Centril Nov 19, 2019
b5166b1
Rollup merge of #66461 - clemencetbk:master, r=GuillaumeGomez
Centril Nov 19, 2019
e99e5fb
Rollup merge of #66493 - JohnTitor:ping-me-rustc-guide, r=spastorino
Centril Nov 19, 2019
42e3b86
Rollup merge of #66511 - haraldh:error_chain_nocopy, r=dtolnay
Centril Nov 19, 2019
1f0f0ad
Rollup merge of #66529 - petrochenkov:reshelp2, r=davidtwco
Centril Nov 19, 2019
0ddd298
Rollup merge of #66536 - nnethercote:mv-QueryResult, r=Centril
Centril Nov 19, 2019
e1a32fa
Rollup merge of #66538 - dingelish:master, r=Centril
Centril Nov 19, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Fix 'type annotations needed' error with opaque types
Related: #66426

This commit adds handling for opaque types during inference variable
fallback. Type variables generated from the instantiatino of opaque
types now fallback to the opque type itself.

Normally, the type variable for an instantiated opaque type is either
unified with the concrete type, or with the opaque type itself (e.g when
a function returns an opaque type by calling another function).

However, it's possible for the type variable to be left completely
unconstrained. This can occur in code like this:

```rust
pub type Foo = impl Copy;
fn produce() -> Option<Foo> {
    None
}
```

Here, we'll instantatiate the `Foo` in `Option<Foo>` to a fresh type
variable, but we will never unify it with anything due to the fact
that we return a `None`.

This results in the error message:

`type annotations needed: cannot resolve `_: std::marker::Copy``

pointing at `pub type Foo = impl Copy`.

This message is not only confusing, it's incorrect. When an opaque type
inference variable is completely unconstrained, we can always fall back
to using the opaque type itself. This effectively turns that particular
use of the opaque type into a non-defining use, even if it appears in a
defining scope.
  • Loading branch information
Aaron1011 committed Nov 18, 2019
commit 0e2ccaaa3e70d85d1243c07e6ac0ef3829115a8d
5 changes: 5 additions & 0 deletions src/librustc/infer/opaque_types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ pub type OpaqueTypeMap<'tcx> = DefIdMap<OpaqueTypeDecl<'tcx>>;
/// appear in the return type).
#[derive(Copy, Clone, Debug)]
pub struct OpaqueTypeDecl<'tcx> {

/// The opaque type (`ty::Opaque`) for this declaration
pub opaque_type: Ty<'tcx>,

/// The substitutions that we apply to the opaque type that this
/// `impl Trait` desugars to. e.g., if:
///
Expand Down Expand Up @@ -1150,6 +1154,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
self.opaque_types.insert(
def_id,
OpaqueTypeDecl {
opaque_type: ty,
substs,
definition_span,
concrete_ty: ty_var,
Expand Down
101 changes: 97 additions & 4 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ use crate::TypeAndSubsts;
use crate::lint;
use crate::util::captures::Captures;
use crate::util::common::{ErrorReported, indenter};
use crate::util::nodemap::{DefIdMap, DefIdSet, FxHashSet, HirIdMap};
use crate::util::nodemap::{DefIdMap, DefIdSet, FxHashMap, FxHashSet, HirIdMap};

pub use self::Expectation::*;
use self::autoderef::Autoderef;
Expand Down Expand Up @@ -231,6 +231,13 @@ pub struct Inherited<'a, 'tcx> {
// 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions.
opaque_types: RefCell<DefIdMap<OpaqueTypeDecl<'tcx>>>,

/// A map from inference variables created from opaque
/// type instantiations (ty::Infer) to the actual opaque
/// type (`ty::Opaque`). Used during fallback to map unconstrained
/// opaque type inference variables to their corresponding
/// opaque type.
opaque_types_vars: RefCell<FxHashMap<Ty<'tcx>, Ty<'tcx>>>,

/// Each type parameter has an implicit region bound that
/// indicates it must outlive at least the function body (the user
/// may specify stronger requirements). This field indicates the
Expand Down Expand Up @@ -696,6 +703,7 @@ impl Inherited<'a, 'tcx> {
deferred_cast_checks: RefCell::new(Vec::new()),
deferred_generator_interiors: RefCell::new(Vec::new()),
opaque_types: RefCell::new(Default::default()),
opaque_types_vars: RefCell::new(Default::default()),
implicit_region_bound,
body_id,
}
Expand Down Expand Up @@ -937,9 +945,46 @@ fn typeck_tables_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::TypeckTables<'_> {
// All type checking constraints were added, try to fallback unsolved variables.
fcx.select_obligations_where_possible(false, |_| {});
let mut fallback_has_occurred = false;

// We do fallback in two passes, to try to generate
// better error messages.
// The first time, we do *not* replace opaque types.
for ty in &fcx.unsolved_variables() {
fallback_has_occurred |= fcx.fallback_if_possible(ty, false /* opaque_fallback */);
}
// We now see if we can make progress. This might
// cause us to unify inference variables for opaque types,
// since we may have unified some other type variables
// during the first phase of fallback.
// This means that we only replace inference variables with their underlying
// opaque types as a last resort.
//
// In code like this:
//
// ```rust
// type MyType = impl Copy;
// fn produce() -> MyType { true }
// fn bad_produce() -> MyType { panic!() }
// ```
//
// we want to unify the opaque inference variable in `bad_produce`
// with the diverging fallback for `panic!` (e.g. `()` or `!`),
// This will produce a nice error message about conflicting concrete
// types for `MyType`.
//
// If we had tried to fallback the opaque inference variable to `MyType`,
// we will generate a confusing type-check error that does not explicitly
// refer to opaque types.
fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});

// We now run fallback again, but this time we allow it to replace
// unconstrained opaque type variables, in addition to performing
// other kinds of fallback.
for ty in &fcx.unsolved_variables() {
fallback_has_occurred |= fcx.fallback_if_possible(ty);
fallback_has_occurred |= fcx.fallback_if_possible(ty, true /* opaque_fallback */);
}

// See if we can make any more progress
fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});

// Even though coercion casts provide type hints, we check casts after fallback for
Expand Down Expand Up @@ -2864,8 +2909,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);

let mut opaque_types = self.opaque_types.borrow_mut();
let mut opaque_types_vars = self.opaque_types_vars.borrow_mut();
for (ty, decl) in opaque_type_map {
let _ = opaque_types.insert(ty, decl);
let _ = opaque_types_vars.insert(decl.concrete_ty, decl.opaque_type);
}

value
Expand Down Expand Up @@ -3078,7 +3125,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Fallback becomes very dubious if we have encountered type-checking errors.
// In that case, fallback to Error.
// The return value indicates whether fallback has occurred.
fn fallback_if_possible(&self, ty: Ty<'tcx>) -> bool {
fn fallback_if_possible(&self, ty: Ty<'tcx>, opaque_fallback: bool) -> bool {
use rustc::ty::error::UnconstrainedNumeric::Neither;
use rustc::ty::error::UnconstrainedNumeric::{UnconstrainedInt, UnconstrainedFloat};

Expand All @@ -3088,7 +3135,53 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
UnconstrainedInt => self.tcx.types.i32,
UnconstrainedFloat => self.tcx.types.f64,
Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(),
Neither => return false,
Neither => {
// This type variable was created from the instantiation of an opaque
// type. The fact that we're attempting to perform fallback for it
// means that the function neither constrained it to a concrete
// type, nor to the opaque type itself.
//
// For example, in this code:
//
//```
// type MyType = impl Copy;
// fn defining_use() -> MyType { true }
// fn other_use() -> MyType { defining_use() }
// ```
//
// `defining_use` will constrain the instantiated inference
// variable to `bool`, while `other_use` will constrain
// the instantiated inference variable to `MyType`.
//
// When we process opaque types during writeback, we
// will handle cases like `other_use`, and not count
// them as defining usages
//
// However, we also need to handle cases like this:
//
// ```rust
// pub type Foo = impl Copy;
// fn produce() -> Option<Foo> {
// None
// }
// ```
//
// In the above snippet, the inference varaible created by
// instantiating `Option<Foo>` will be completely unconstrained.
// We treat this as a non-defining use by making the inference
// variable fall back to the opaque type itself.
if opaque_fallback {
if let Some(opaque_ty) = self.opaque_types_vars.borrow().get(ty) {
debug!("fallback_if_possible: falling back opaque type var {:?} to {:?}",
ty, opaque_ty);
*opaque_ty
} else {
return false;
}
} else {
return false;
}
},
};
debug!("fallback_if_possible: defaulting `{:?}` to `{:?}`", ty, fallback);
self.demand_eqtype(syntax_pos::DUMMY_SP, ty, fallback);
Expand Down
9 changes: 9 additions & 0 deletions src/test/ui/impl-trait/where-allowed-2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//! Ideally, these tests would go in `where-allowed.rs`, but we bail out
//! too early to display them.
use std::fmt::Debug;

// Disallowed
fn in_adt_in_return() -> Vec<impl Debug> { panic!() }
//~^ ERROR opaque type expands to a recursive type

fn main() {}
11 changes: 11 additions & 0 deletions src/test/ui/impl-trait/where-allowed-2.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0720]: opaque type expands to a recursive type
--> $DIR/where-allowed-2.rs:6:30
|
LL | fn in_adt_in_return() -> Vec<impl Debug> { panic!() }
| ^^^^^^^^^^ expands to a recursive type
|
= note: type resolves to itself

error: aborting due to previous error

For more information about this error, try `rustc --explain E0720`.
5 changes: 0 additions & 5 deletions src/test/ui/impl-trait/where-allowed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,6 @@ fn in_return() -> impl Debug { panic!() }
// Allowed
fn in_adt_in_parameters(_: Vec<impl Debug>) { panic!() }

// Disallowed
fn in_adt_in_return() -> Vec<impl Debug> { panic!() }
//~^ ERROR type annotations needed

// Disallowed
fn in_fn_parameter_in_parameters(_: fn(impl Debug)) { panic!() }
//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
Expand Down Expand Up @@ -60,7 +56,6 @@ fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() }
fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() }
//~^ ERROR `impl Trait` not allowed outside of function and inherent method return types
//~| ERROR nested `impl Trait` is not allowed
//~| ERROR type annotations needed

// Disallowed
fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() }
Expand Down
22 changes: 22 additions & 0 deletions src/test/ui/type-alias-impl-trait/fallback.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Tests that we correctly handle the instantiated
// inference variable being completely unconstrained.
//
// check-pass
#![feature(type_alias_impl_trait)]

type Foo = impl Copy;

enum Wrapper<T> {
First(T),
Second
}

fn _make_iter() -> Foo {
true
}

fn _produce() -> Wrapper<Foo> {
Wrapper::Second
}

fn main() {}