Skip to content
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

Rollup of 4 pull requests #82306

Closed
wants to merge 12 commits into from
2 changes: 1 addition & 1 deletion compiler/rustc_driver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -813,7 +813,7 @@ fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) {
} else {
"\n --help -v Print the full set of options rustc accepts"
};
let at_path = if verbose && nightly_build {
let at_path = if verbose {
" @path Read newline separated options from `path`\n"
} else {
""
Expand Down
17 changes: 15 additions & 2 deletions compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1074,13 +1074,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let last_expr_ty = self.node_ty(last_expr.hir_id);
let needs_box = match (last_expr_ty.kind(), expected_ty.kind()) {
(ty::Opaque(last_def_id, _), ty::Opaque(exp_def_id, _))
if last_def_id == exp_def_id =>
{
StatementAsExpression::CorrectType
}
(ty::Opaque(last_def_id, last_bounds), ty::Opaque(exp_def_id, exp_bounds)) => {
debug!(
"both opaque, likely future {:?} {:?} {:?} {:?}",
last_def_id, last_bounds, exp_def_id, exp_bounds
);
let last_hir_id = self.tcx.hir().local_def_id_to_hir_id(last_def_id.expect_local());
let exp_hir_id = self.tcx.hir().local_def_id_to_hir_id(exp_def_id.expect_local());

let (last_local_id, exp_local_id) =
match (last_def_id.as_local(), exp_def_id.as_local()) {
(Some(last_hir_id), Some(exp_hir_id)) => (last_hir_id, exp_hir_id),
(_, _) => return None,
};

let last_hir_id = self.tcx.hir().local_def_id_to_hir_id(last_local_id);
let exp_hir_id = self.tcx.hir().local_def_id_to_hir_id(exp_local_id);

match (
&self.tcx.hir().expect_item(last_hir_id).kind,
&self.tcx.hir().expect_item(exp_hir_id).kind,
Expand Down
4 changes: 2 additions & 2 deletions library/std/src/io/stdio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,8 @@ pub struct Stdin {
/// let mut buffer = String::new();
/// let stdin = io::stdin(); // We get `Stdin` here.
/// {
/// let mut stdin_lock = stdin.lock(); // We get `StdinLock` here.
/// stdin_lock.read_to_string(&mut buffer)?;
/// let mut handle = stdin.lock(); // We get `StdinLock` here.
/// handle.read_to_string(&mut buffer)?;
/// } // `StdinLock` is dropped here.
/// Ok(())
/// }
Expand Down
204 changes: 114 additions & 90 deletions src/librustdoc/clean/auto_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,107 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
AutoTraitFinder { cx }
}

fn generate_for_trait(
&mut self,
ty: Ty<'tcx>,
trait_def_id: DefId,
param_env: ty::ParamEnv<'tcx>,
param_env_def_id: DefId,
f: &auto_trait::AutoTraitFinder<'tcx>,
// If this is set, show only negative trait implementations, not positive ones.
discard_positive_impl: bool,
) -> Option<Item> {
let tcx = self.cx.tcx;
let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, &[]) };
if !self.cx.generated_synthetics.borrow_mut().insert((ty, trait_def_id)) {
debug!("get_auto_trait_impl_for({:?}): already generated, aborting", trait_ref);
return None;
}

let result = f.find_auto_trait_generics(ty, param_env, trait_def_id, |infcx, info| {
let region_data = info.region_data;

let names_map = tcx
.generics_of(param_env_def_id)
.params
.iter()
.filter_map(|param| match param.kind {
ty::GenericParamDefKind::Lifetime => Some(param.name),
_ => None,
})
.map(|name| (name, Lifetime(name)))
.collect();
let lifetime_predicates = Self::handle_lifetimes(&region_data, &names_map);
let new_generics = self.param_env_to_generics(
infcx.tcx,
param_env_def_id,
info.full_user_env,
lifetime_predicates,
info.vid_to_region,
);

debug!(
"find_auto_trait_generics(param_env_def_id={:?}, trait_def_id={:?}): \
finished with {:?}",
param_env_def_id, trait_def_id, new_generics
);

new_generics
});

let negative_polarity;
let new_generics = match result {
AutoTraitResult::PositiveImpl(new_generics) => {
negative_polarity = false;
if discard_positive_impl {
return None;
}
new_generics
}
AutoTraitResult::NegativeImpl => {
negative_polarity = true;

// For negative impls, we use the generic params, but *not* the predicates,
// from the original type. Otherwise, the displayed impl appears to be a
// conditional negative impl, when it's really unconditional.
//
// For example, consider the struct Foo<T: Copy>(*mut T). Using
// the original predicates in our impl would cause us to generate
// `impl !Send for Foo<T: Copy>`, which makes it appear that Foo
// implements Send where T is not copy.
//
// Instead, we generate `impl !Send for Foo<T>`, which better
// expresses the fact that `Foo<T>` never implements `Send`,
// regardless of the choice of `T`.
let params = (tcx.generics_of(param_env_def_id), ty::GenericPredicates::default())
.clean(self.cx)
.params;

Generics { params, where_predicates: Vec::new() }
}
AutoTraitResult::ExplicitImpl => return None,
};

Some(Item {
source: Span::dummy(),
name: None,
attrs: Default::default(),
visibility: Inherited,
def_id: self.cx.next_def_id(param_env_def_id.krate),
kind: box ImplItem(Impl {
unsafety: hir::Unsafety::Normal,
generics: new_generics,
provided_trait_methods: Default::default(),
trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()),
for_: ty.clean(self.cx),
items: Vec::new(),
negative_polarity,
synthetic: true,
blanket_impl: None,
}),
})
}

// FIXME(eddyb) figure out a better way to pass information about
// parametrization of `ty` than `param_env_def_id`.
crate fn get_auto_trait_impls(&mut self, ty: Ty<'tcx>, param_env_def_id: DefId) -> Vec<Item> {
Expand All @@ -38,99 +139,22 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {

debug!("get_auto_trait_impls({:?})", ty);
let auto_traits: Vec<_> = self.cx.auto_traits.iter().cloned().collect();
auto_traits
let mut auto_traits: Vec<Item> = auto_traits
.into_iter()
.filter_map(|trait_def_id| {
let trait_ref =
ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, &[]) };
if !self.cx.generated_synthetics.borrow_mut().insert((ty, trait_def_id)) {
debug!("get_auto_trait_impl_for({:?}): already generated, aborting", trait_ref);
return None;
}

let result =
f.find_auto_trait_generics(ty, param_env, trait_def_id, |infcx, info| {
let region_data = info.region_data;

let names_map = tcx
.generics_of(param_env_def_id)
.params
.iter()
.filter_map(|param| match param.kind {
ty::GenericParamDefKind::Lifetime => Some(param.name),
_ => None,
})
.map(|name| (name, Lifetime(name)))
.collect();
let lifetime_predicates = Self::handle_lifetimes(&region_data, &names_map);
let new_generics = self.param_env_to_generics(
infcx.tcx,
param_env_def_id,
info.full_user_env,
lifetime_predicates,
info.vid_to_region,
);

debug!(
"find_auto_trait_generics(param_env_def_id={:?}, trait_def_id={:?}): \
finished with {:?}",
param_env_def_id, trait_def_id, new_generics
);

new_generics
});

let negative_polarity;
let new_generics = match result {
AutoTraitResult::PositiveImpl(new_generics) => {
negative_polarity = false;
new_generics
}
AutoTraitResult::NegativeImpl => {
negative_polarity = true;

// For negative impls, we use the generic params, but *not* the predicates,
// from the original type. Otherwise, the displayed impl appears to be a
// conditional negative impl, when it's really unconditional.
//
// For example, consider the struct Foo<T: Copy>(*mut T). Using
// the original predicates in our impl would cause us to generate
// `impl !Send for Foo<T: Copy>`, which makes it appear that Foo
// implements Send where T is not copy.
//
// Instead, we generate `impl !Send for Foo<T>`, which better
// expresses the fact that `Foo<T>` never implements `Send`,
// regardless of the choice of `T`.
let params =
(tcx.generics_of(param_env_def_id), ty::GenericPredicates::default())
.clean(self.cx)
.params;

Generics { params, where_predicates: Vec::new() }
}
AutoTraitResult::ExplicitImpl => return None,
};

Some(Item {
source: Span::dummy(),
name: None,
attrs: Default::default(),
visibility: Inherited,
def_id: self.cx.next_def_id(param_env_def_id.krate),
kind: box ImplItem(Impl {
unsafety: hir::Unsafety::Normal,
generics: new_generics,
provided_trait_methods: Default::default(),
trait_: Some(trait_ref.clean(self.cx).get_trait_type().unwrap()),
for_: ty.clean(self.cx),
items: Vec::new(),
negative_polarity,
synthetic: true,
blanket_impl: None,
}),
})
self.generate_for_trait(ty, trait_def_id, param_env, param_env_def_id, &f, false)
})
.collect()
.collect();
// We are only interested in case the type *doesn't* implement the Sized trait.
if !ty.is_sized(self.cx.tcx.at(rustc_span::DUMMY_SP), param_env) {
// In case `#![no_core]` is used, `sized_trait` returns nothing.
if let Some(item) = self.cx.tcx.lang_items().sized_trait().and_then(|sized_trait_did| {
self.generate_for_trait(ty, sized_trait_did, param_env, param_env_def_id, &f, true)
}) {
auto_traits.push(item);
}
}
auto_traits
}

fn get_lifetime(region: Region<'_>, names_map: &FxHashMap<Symbol, Lifetime>) -> Lifetime {
Expand Down
11 changes: 11 additions & 0 deletions src/librustdoc/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ use std::{
};

use crate::clean;
use crate::clean::inline::build_external_trait;
use crate::clean::{AttributesExt, MAX_DEF_IDX};
use crate::config::{Options as RustdocOptions, RenderOptions};
use crate::config::{OutputFormat, RenderInfo};
Expand Down Expand Up @@ -530,6 +531,16 @@ crate fn run_global_ctxt(
module_trait_cache: RefCell::new(FxHashMap::default()),
cache: Cache::default(),
};

// Small hack to force the Sized trait to be present.
//
// Note that in case of `#![no_core]`, the trait is not available.
if let Some(sized_trait_did) = ctxt.tcx.lang_items().sized_trait() {
let mut sized_trait = build_external_trait(&mut ctxt, sized_trait_did);
sized_trait.is_auto = true;
ctxt.external_traits.borrow_mut().insert(sized_trait_did, sized_trait);
}

debug!("crate: {:?}", tcx.hir().krate());

let mut krate = tcx.sess.time("clean_crate", || clean::krate(&mut ctxt));
Expand Down
17 changes: 17 additions & 0 deletions src/test/rustdoc/sized_trait.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#![crate_name = "foo"]

// @has foo/struct.Bar.html
// @!has - '//h3[@id="impl-Sized"]'
pub struct Bar {
a: u16,
}

// @has foo/struct.Foo.html
// @!has - '//h3[@id="impl-Sized"]'
pub struct Foo<T: ?Sized>(T);

// @has foo/struct.Unsized.html
// @has - '//h3[@id="impl-Sized"]/code' 'impl !Sized for Unsized'
pub struct Unsized {
data: [u8],
}
9 changes: 9 additions & 0 deletions src/test/ui/suggestions/auxiliary/issue-81839.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// edition:2018

pub struct Test {}

impl Test {
pub async fn answer_str(&self, _s: &str) -> Test {
Test {}
}
}
17 changes: 17 additions & 0 deletions src/test/ui/suggestions/issue-81839.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// aux-build:issue-81839.rs
// edition:2018

extern crate issue_81839;

async fn test(ans: &str, num: i32, cx: &issue_81839::Test) -> u32 {
match num {
1 => {
cx.answer_str("hi");
}
_ => cx.answer_str("hi"), //~ `match` arms have incompatible types
}

1
}

fn main() {}
27 changes: 27 additions & 0 deletions src/test/ui/suggestions/issue-81839.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
error[E0308]: `match` arms have incompatible types
--> $DIR/issue-81839.rs:11:14
|
LL | / match num {
LL | | 1 => {
LL | | cx.answer_str("hi");
| | --------------------
| | | |
| | | help: consider removing this semicolon
| | this is found to be of type `()`
LL | | }
LL | | _ => cx.answer_str("hi"),
| | ^^^^^^^^^^^^^^^^^^^ expected `()`, found opaque type
LL | | }
| |_____- `match` arms have incompatible types
|
::: $DIR/auxiliary/issue-81839.rs:6:49
|
LL | pub async fn answer_str(&self, _s: &str) -> Test {
| ---- the `Output` of this `async fn`'s found opaque type
|
= note: expected type `()`
found opaque type `impl Future`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
9 changes: 3 additions & 6 deletions src/test/ui/suggestions/match-prev-arm-needing-semi.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,10 @@ help: consider `await`ing on the `Future`
|
LL | false => async_dummy().await,
| ^^^^^^
help: consider removing this semicolon and boxing the expressions
|
LL | Box::new(async_dummy())
LL |
LL | }
LL | false => Box::new(async_dummy()),
help: consider removing this semicolon
|
LL | async_dummy()
| --

error[E0308]: `match` arms have incompatible types
--> $DIR/match-prev-arm-needing-semi.rs:39:18
Expand Down