Auto merge of #103829 - JohnTitor:rollup-o03nzr8, r=JohnTitor
Rollup of 10 pull requests Successful merges: - #103007 (Add better python discovery) - #103674 (Update note about unstable split-debuginfo flag.) - #103692 (Add `walk_generic_arg`) - #103749 (Reduce span of let else irrefutable_let_patterns warning) - #103772 (better error for `rustc_strict_coherence` misuse) - #103788 (Fix ICE in checking transmutability of NaughtyLenArray) - #103793 (rustdoc: add margins to all impl-item toggles, not just methods) - #103798 (interpret: move type_name implementation to an interpreter-independent helper file) - #103799 (Remove generation of tuple struct fields in the search index) - #103805 (Enable RUSTC_BOOTSTRAP for a few steps) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
dc05f60c1f
@ -7,7 +7,9 @@ use std::convert::TryFrom;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::mir::{
|
||||
self,
|
||||
interpret::{ConstValue, GlobalId, InterpResult, PointerArithmetic, Scalar},
|
||||
interpret::{
|
||||
Allocation, ConstAllocation, ConstValue, GlobalId, InterpResult, PointerArithmetic, Scalar,
|
||||
},
|
||||
BinOp, NonDivergingIntrinsic,
|
||||
};
|
||||
use rustc_middle::ty;
|
||||
@ -23,7 +25,6 @@ use super::{
|
||||
};
|
||||
|
||||
mod caller_location;
|
||||
mod type_name;
|
||||
|
||||
fn numeric_intrinsic<Prov>(name: Symbol, bits: u128, kind: Primitive) -> Scalar<Prov> {
|
||||
let size = match kind {
|
||||
@ -42,6 +43,13 @@ fn numeric_intrinsic<Prov>(name: Symbol, bits: u128, kind: Primitive) -> Scalar<
|
||||
Scalar::from_uint(bits_out, size)
|
||||
}
|
||||
|
||||
/// Directly returns an `Allocation` containing an absolute path representation of the given type.
|
||||
pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAllocation<'tcx> {
|
||||
let path = crate::util::type_name(tcx, ty);
|
||||
let alloc = Allocation::from_bytes_byte_aligned_immutable(path.into_bytes());
|
||||
tcx.intern_const_alloc(alloc)
|
||||
}
|
||||
|
||||
/// The logic for all nullary intrinsics is implemented here. These intrinsics don't get evaluated
|
||||
/// inside an `InterpCx` and instead have their value computed directly from rustc internal info.
|
||||
pub(crate) fn eval_nullary_intrinsic<'tcx>(
|
||||
@ -55,7 +63,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
|
||||
Ok(match name {
|
||||
sym::type_name => {
|
||||
ensure_monomorphic_enough(tcx, tp_ty)?;
|
||||
let alloc = type_name::alloc_type_name(tcx, tp_ty);
|
||||
let alloc = alloc_type_name(tcx, tp_ty);
|
||||
ConstValue::Slice { data: alloc, start: 0, end: alloc.inner().len() }
|
||||
}
|
||||
sym::needs_drop => {
|
||||
|
@ -4,9 +4,11 @@ mod call_kind;
|
||||
pub mod collect_writes;
|
||||
mod find_self_call;
|
||||
mod might_permit_raw_init;
|
||||
mod type_name;
|
||||
|
||||
pub use self::aggregate::expand_aggregate;
|
||||
pub use self::alignment::is_disaligned;
|
||||
pub use self::call_kind::{call_kind, CallDesugaringKind, CallKind};
|
||||
pub use self::find_self_call::find_self_call;
|
||||
pub use self::might_permit_raw_init::might_permit_raw_init;
|
||||
pub use self::type_name::type_name;
|
||||
|
@ -1,7 +1,6 @@
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_hir::def_id::CrateNum;
|
||||
use rustc_hir::definitions::DisambiguatedDefPathData;
|
||||
use rustc_middle::mir::interpret::{Allocation, ConstAllocation};
|
||||
use rustc_middle::ty::{
|
||||
self,
|
||||
print::{PrettyPrinter, Print, Printer},
|
||||
@ -193,9 +192,6 @@ impl Write for AbsolutePathPrinter<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Directly returns an `Allocation` containing an absolute path representation of the given type.
|
||||
pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAllocation<'tcx> {
|
||||
let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path;
|
||||
let alloc = Allocation::from_bytes_byte_aligned_immutable(path.into_bytes());
|
||||
tcx.intern_const_alloc(alloc)
|
||||
pub fn type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> String {
|
||||
AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path
|
||||
}
|
@ -27,3 +27,7 @@ middle_values_too_big =
|
||||
|
||||
middle_cannot_be_normalized =
|
||||
unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized
|
||||
|
||||
middle_strict_coherence_needs_negative_coherence =
|
||||
to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled
|
||||
.label = due to this attribute
|
||||
|
@ -410,12 +410,7 @@ pub trait Visitor<'v>: Sized {
|
||||
walk_inf(self, inf);
|
||||
}
|
||||
fn visit_generic_arg(&mut self, generic_arg: &'v GenericArg<'v>) {
|
||||
match generic_arg {
|
||||
GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
|
||||
GenericArg::Type(ty) => self.visit_ty(ty),
|
||||
GenericArg::Const(ct) => self.visit_anon_const(&ct.value),
|
||||
GenericArg::Infer(inf) => self.visit_infer(inf),
|
||||
}
|
||||
walk_generic_arg(self, generic_arg);
|
||||
}
|
||||
fn visit_lifetime(&mut self, lifetime: &'v Lifetime) {
|
||||
walk_lifetime(self, lifetime)
|
||||
@ -480,6 +475,15 @@ pub fn walk_label<'v, V: Visitor<'v>>(visitor: &mut V, label: &'v Label) {
|
||||
visitor.visit_ident(label.ident);
|
||||
}
|
||||
|
||||
pub fn walk_generic_arg<'v, V: Visitor<'v>>(visitor: &mut V, generic_arg: &'v GenericArg<'v>) {
|
||||
match generic_arg {
|
||||
GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt),
|
||||
GenericArg::Type(ty) => visitor.visit_ty(ty),
|
||||
GenericArg::Const(ct) => visitor.visit_anon_const(&ct.value),
|
||||
GenericArg::Infer(inf) => visitor.visit_infer(inf),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
|
||||
visitor.visit_id(lifetime.hir_id);
|
||||
match lifetime.name {
|
||||
|
@ -55,3 +55,12 @@ pub struct ConstEvalNonIntError {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(middle_strict_coherence_needs_negative_coherence)]
|
||||
pub(crate) struct StrictCoherenceNeedsNegativeCoherence {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label]
|
||||
pub attr_span: Option<Span>,
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::error::StrictCoherenceNeedsNegativeCoherence;
|
||||
use crate::ty::fast_reject::SimplifiedType;
|
||||
use crate::ty::visit::TypeVisitable;
|
||||
use crate::ty::{self, TyCtxt};
|
||||
@ -65,9 +66,21 @@ impl OverlapMode {
|
||||
|
||||
if with_negative_coherence {
|
||||
if strict_coherence { OverlapMode::Strict } else { OverlapMode::WithNegative }
|
||||
} else if strict_coherence {
|
||||
bug!("To use strict_coherence you need to set with_negative_coherence feature flag");
|
||||
} else {
|
||||
if strict_coherence {
|
||||
let attr_span = trait_id
|
||||
.as_local()
|
||||
.into_iter()
|
||||
.flat_map(|local_def_id| {
|
||||
tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(local_def_id))
|
||||
})
|
||||
.find(|attr| attr.has_name(sym::rustc_strict_coherence))
|
||||
.map(|attr| attr.span);
|
||||
tcx.sess.emit_err(StrictCoherenceNeedsNegativeCoherence {
|
||||
span: tcx.def_span(trait_id),
|
||||
attr_span,
|
||||
});
|
||||
}
|
||||
OverlapMode::Stable
|
||||
}
|
||||
}
|
||||
|
@ -79,7 +79,10 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> {
|
||||
intravisit::walk_local(self, loc);
|
||||
let els = loc.els;
|
||||
if let Some(init) = loc.init && els.is_some() {
|
||||
self.check_let(&loc.pat, init, loc.span);
|
||||
// Build a span without the else { ... } as we don't want to underline
|
||||
// the entire else block in the IDE setting.
|
||||
let span = loc.span.with_hi(init.span.hi());
|
||||
self.check_let(&loc.pat, init, span);
|
||||
}
|
||||
|
||||
let (msg, sp) = match loc.source {
|
||||
@ -630,11 +633,6 @@ fn irrefutable_let_patterns(
|
||||
count: usize,
|
||||
span: Span,
|
||||
) {
|
||||
let span = match source {
|
||||
LetSource::LetElse(span) => span,
|
||||
_ => span,
|
||||
};
|
||||
|
||||
macro_rules! emit_diag {
|
||||
(
|
||||
$lint:expr,
|
||||
@ -680,7 +678,7 @@ fn irrefutable_let_patterns(
|
||||
"removing the guard and adding a `let` inside the match arm"
|
||||
);
|
||||
}
|
||||
LetSource::LetElse(..) => {
|
||||
LetSource::LetElse => {
|
||||
emit_diag!(
|
||||
lint,
|
||||
"`let...else`",
|
||||
@ -1127,7 +1125,7 @@ pub enum LetSource {
|
||||
GenericLet,
|
||||
IfLet,
|
||||
IfLetGuard,
|
||||
LetElse(Span),
|
||||
LetElse,
|
||||
WhileLet,
|
||||
}
|
||||
|
||||
@ -1156,8 +1154,8 @@ fn let_source_parent(tcx: TyCtxt<'_>, parent: HirId, pat_id: Option<HirId>) -> L
|
||||
let parent_parent = hir.get_parent_node(parent);
|
||||
let parent_parent_node = hir.get(parent_parent);
|
||||
match parent_parent_node {
|
||||
hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_), span, .. }) => {
|
||||
return LetSource::LetElse(*span);
|
||||
hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_), .. }) => {
|
||||
return LetSource::LetElse;
|
||||
}
|
||||
hir::Node::Arm(hir::Arm { guard: Some(hir::Guard::If(_)), .. }) => {
|
||||
return LetSource::IfLetGuard;
|
||||
|
@ -284,7 +284,8 @@ pub(crate) mod rustc {
|
||||
}
|
||||
|
||||
ty::Array(ty, len) => {
|
||||
let len = len.try_eval_usize(tcx, ParamEnv::reveal_all()).unwrap();
|
||||
let len =
|
||||
len.try_eval_usize(tcx, ParamEnv::reveal_all()).ok_or(Err::Unspecified)?;
|
||||
let elt = Tree::from_ty(*ty, tcx)?;
|
||||
Ok(std::iter::repeat(elt)
|
||||
.take(len as usize)
|
||||
|
@ -986,6 +986,7 @@ impl Step for RustdocGUI {
|
||||
.arg("doc")
|
||||
.arg("--target-dir")
|
||||
.arg(&out_dir)
|
||||
.env("RUSTC_BOOTSTRAP", "1")
|
||||
.env("RUSTDOC", builder.rustdoc(self.compiler))
|
||||
.env("RUSTC", builder.rustc(self.compiler))
|
||||
.current_dir(path);
|
||||
@ -1725,6 +1726,8 @@ impl BookTest {
|
||||
|
||||
let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
|
||||
let path = builder.src.join(&self.path);
|
||||
// Books often have feature-gated example text.
|
||||
rustbook_cmd.env("RUSTC_BOOTSTRAP", "1");
|
||||
rustbook_cmd.env("PATH", new_path).arg("test").arg(path);
|
||||
builder.add_rust_test_threads(&mut rustbook_cmd);
|
||||
builder.info(&format!("Testing rustbook {}", self.path.display()));
|
||||
|
@ -531,8 +531,10 @@ platforms. Possible values are:
|
||||
debug information. On other Unix platforms this means that `*.dwo` files will
|
||||
contain debug information.
|
||||
|
||||
Note that `packed` and `unpacked` are gated behind `-Z unstable-options` on
|
||||
non-macOS platforms at this time.
|
||||
Note that all three options are supported on Linux and Apple platforms,
|
||||
`packed` is supported on Windows-MSVC, and all other platforms support `off`.
|
||||
Attempting to use an unsupported option requires using the nightly channel
|
||||
with the `-Z unstable-options` flag.
|
||||
|
||||
## strip
|
||||
|
||||
|
@ -316,21 +316,28 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
|
||||
let desc = item.doc_value().map_or_else(String::new, |x| {
|
||||
short_markdown_summary(x.as_str(), &item.link_names(self.cache))
|
||||
});
|
||||
self.cache.search_index.push(IndexItem {
|
||||
ty: item.type_(),
|
||||
name: s.to_string(),
|
||||
path: join_with_double_colon(path),
|
||||
desc,
|
||||
parent,
|
||||
parent_idx: None,
|
||||
search_type: get_function_type_for_search(
|
||||
&item,
|
||||
self.tcx,
|
||||
clean_impl_generics(self.cache.parent_stack.last()).as_ref(),
|
||||
self.cache,
|
||||
),
|
||||
aliases: item.attrs.get_doc_aliases(),
|
||||
});
|
||||
let ty = item.type_();
|
||||
let name = s.to_string();
|
||||
if ty != ItemType::StructField || u16::from_str_radix(&name, 10).is_err() {
|
||||
// In case this is a field from a tuple struct, we don't add it into
|
||||
// the search index because its name is something like "0", which is
|
||||
// not useful for rustdoc search.
|
||||
self.cache.search_index.push(IndexItem {
|
||||
ty,
|
||||
name,
|
||||
path: join_with_double_colon(path),
|
||||
desc,
|
||||
parent,
|
||||
parent_idx: None,
|
||||
search_type: get_function_type_for_search(
|
||||
&item,
|
||||
self.tcx,
|
||||
clean_impl_generics(self.cache.parent_stack.last()).as_ref(),
|
||||
self.cache,
|
||||
),
|
||||
aliases: item.attrs.get_doc_aliases(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
(Some(parent), None) if is_inherent_impl_item => {
|
||||
|
@ -1968,24 +1968,26 @@ in storage.js
|
||||
}
|
||||
}
|
||||
|
||||
.method-toggle > summary,
|
||||
.implementors-toggle > summary,
|
||||
.impl,
|
||||
#implementors-list > .docblock,
|
||||
.impl-items > section,
|
||||
.methods > section
|
||||
.impl-items > .rustdoc-toggle > summary,
|
||||
.methods > section,
|
||||
.methods > .rustdoc-toggle > summary
|
||||
{
|
||||
margin-bottom: 0.75em;
|
||||
}
|
||||
|
||||
.method-toggle[open]:not(:last-child),
|
||||
.impl-items > .rustdoc-toggle[open]:not(:last-child),
|
||||
.methods > .rustdoc-toggle[open]:not(:last-child),
|
||||
.implementors-toggle[open]:not(:last-child) {
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
#trait-implementations-list .method-toggle:not(:last-child),
|
||||
#synthetic-implementations-list .method-toggle:not(:last-child),
|
||||
#blanket-implementations-list .method-toggle:not(:last-child) {
|
||||
#trait-implementations-list .impl-items > .rustdoc-toggle:not(:last-child),
|
||||
#synthetic-implementations-list .impl-items > .rustdoc-toggle:not(:last-child),
|
||||
#blanket-implementations-list .impl-items > .rustdoc-toggle:not(:last-child) {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
|
17
src/test/rustdoc-gui/method-margins.goml
Normal file
17
src/test/rustdoc-gui/method-margins.goml
Normal file
@ -0,0 +1,17 @@
|
||||
goto: "file://" + |DOC_PATH| + "/test_docs/trait_members/struct.HasTrait.html#impl-TraitMembers-for-HasTrait"
|
||||
|
||||
assert-count: ("#trait-implementations-list > .rustdoc-toggle", 1)
|
||||
|
||||
compare-elements-css: (
|
||||
// compare margin on type with margin on method
|
||||
"#trait-implementations-list .impl-items > .rustdoc-toggle:nth-child(1) > summary",
|
||||
"#trait-implementations-list .impl-items > .rustdoc-toggle:nth-child(2) > summary",
|
||||
["margin"]
|
||||
)
|
||||
|
||||
compare-elements-css: (
|
||||
// compare margin on type with margin on method
|
||||
"#trait-implementations-list .impl-items > .rustdoc-toggle:nth-child(1)",
|
||||
"#trait-implementations-list .impl-items > .rustdoc-toggle:nth-child(2)",
|
||||
["margin"]
|
||||
)
|
@ -416,3 +416,20 @@ pub trait TraitWithoutGenerics {
|
||||
|
||||
fn foo();
|
||||
}
|
||||
|
||||
pub mod trait_members {
|
||||
pub trait TraitMembers {
|
||||
/// Some type
|
||||
type Type;
|
||||
/// Some function
|
||||
fn function();
|
||||
/// Some other function
|
||||
fn function2();
|
||||
}
|
||||
pub struct HasTrait;
|
||||
impl TraitMembers for HasTrait {
|
||||
type Type = u8;
|
||||
fn function() {}
|
||||
fn function2() {}
|
||||
}
|
||||
}
|
||||
|
18
src/test/rustdoc/no-unit-struct-field.rs
Normal file
18
src/test/rustdoc/no-unit-struct-field.rs
Normal file
@ -0,0 +1,18 @@
|
||||
// This test ensures that the tuple struct fields are not generated in the
|
||||
// search index.
|
||||
|
||||
// @!hasraw search-index.js '"0"'
|
||||
// @!hasraw search-index.js '"1"'
|
||||
// @hasraw search-index.js '"foo_a"'
|
||||
// @hasraw search-index.js '"bar_a"'
|
||||
|
||||
pub struct Bar(pub u32, pub u8);
|
||||
pub struct Foo {
|
||||
pub foo_a: u8,
|
||||
}
|
||||
pub enum Enum {
|
||||
Foo(u8),
|
||||
Bar {
|
||||
bar_a: u8,
|
||||
},
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
#[rustc_strict_coherence]
|
||||
trait Foo {}
|
||||
//~^ ERROR to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,10 @@
|
||||
error: to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled
|
||||
--> $DIR/strict-coherence-needs-negative-coherence.rs:4:1
|
||||
|
|
||||
LL | #[rustc_strict_coherence]
|
||||
| ------------------------- due to this attribute
|
||||
LL | trait Foo {}
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -1,7 +1,11 @@
|
||||
// check-pass
|
||||
|
||||
|
||||
|
||||
fn main() {
|
||||
let x = 1 else { return }; //~ WARN irrefutable `let...else` pattern
|
||||
|
||||
// Multiline else blocks should not get printed
|
||||
let x = 1 else { //~ WARN irrefutable `let...else` pattern
|
||||
eprintln!("problem case encountered");
|
||||
return
|
||||
};
|
||||
}
|
||||
|
@ -1,12 +1,21 @@
|
||||
warning: irrefutable `let...else` pattern
|
||||
--> $DIR/let-else-irrefutable.rs:6:5
|
||||
--> $DIR/let-else-irrefutable.rs:4:5
|
||||
|
|
||||
LL | let x = 1 else { return };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: this pattern will always match, so the `else` clause is useless
|
||||
= help: consider removing the `else` clause
|
||||
= note: `#[warn(irrefutable_let_patterns)]` on by default
|
||||
|
||||
warning: 1 warning emitted
|
||||
warning: irrefutable `let...else` pattern
|
||||
--> $DIR/let-else-irrefutable.rs:7:5
|
||||
|
|
||||
LL | let x = 1 else {
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: this pattern will always match, so the `else` clause is useless
|
||||
= help: consider removing the `else` clause
|
||||
|
||||
warning: 2 warnings emitted
|
||||
|
||||
|
@ -0,0 +1,24 @@
|
||||
#![crate_type = "lib"]
|
||||
#![feature(transmutability)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
mod assert {
|
||||
use std::mem::{Assume, BikeshedIntrinsicFrom};
|
||||
pub struct Context;
|
||||
|
||||
pub fn is_maybe_transmutable<Src, Dst>()
|
||||
where
|
||||
Dst: BikeshedIntrinsicFrom<
|
||||
Src,
|
||||
Context,
|
||||
{ Assume { alignment: true, lifetimes: true, safety: true, validity: true } },
|
||||
>,
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
fn test() {
|
||||
type NaughtyLenArray = [u32; 3.14159]; //~ ERROR mismatched types
|
||||
type JustUnit = ();
|
||||
assert::is_maybe_transmutable::<JustUnit, NaughtyLenArray>();
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-103783-array-length.rs:21:34
|
||||
|
|
||||
LL | type NaughtyLenArray = [u32; 3.14159];
|
||||
| ^^^^^^^ expected `usize`, found floating-point number
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
6
x
6
x
@ -29,5 +29,11 @@ for SEARCH_PYTHON in py python3 python python2; do
|
||||
exec "$python" $extra_arg "$xpy" "$@"
|
||||
fi
|
||||
done
|
||||
|
||||
python=$(bash -c "compgen -c python" | grep '^python[2-3]\.[0-9]\+$' | head -n1)
|
||||
if ! [ "$python" = "" ]; then
|
||||
exec "$python" "$xpy" "$@"
|
||||
fi
|
||||
|
||||
echo "$0: error: did not find python installed" >&2
|
||||
exit 1
|
||||
|
13
x.ps1
13
x.ps1
@ -10,11 +10,15 @@ foreach ($arg in $args) {
|
||||
$xpy_args += """$arg"""
|
||||
}
|
||||
|
||||
function Get-Application($app) {
|
||||
return Get-Command $app -ErrorAction SilentlyContinue -CommandType Application
|
||||
}
|
||||
|
||||
foreach ($python in "py", "python3", "python", "python2") {
|
||||
# NOTE: this only tests that the command exists in PATH, not that it's actually
|
||||
# executable. The latter is not possible in a portable way, see
|
||||
# https://github.com/PowerShell/PowerShell/issues/12625.
|
||||
if (Get-Command $python -ErrorAction SilentlyContinue) {
|
||||
if (Get-Application $python) {
|
||||
if ($python -eq "py") {
|
||||
# Use python3, not python2
|
||||
$xpy_args = @("-3") + $xpy_args
|
||||
@ -24,5 +28,12 @@ foreach ($python in "py", "python3", "python", "python2") {
|
||||
}
|
||||
}
|
||||
|
||||
$found = (Get-Application "python*" | Where-Object {$_.name -match '^python[2-3]\.[0-9]+(\.exe)?$'})
|
||||
if (($null -ne $found) -and ($found.Length -ge 1)) {
|
||||
$python = $found[0]
|
||||
$process = Start-Process -NoNewWindow -Wait -PassThru $python $xpy_args
|
||||
Exit $process.ExitCode
|
||||
}
|
||||
|
||||
Write-Error "${PSCommandPath}: error: did not find python installed"
|
||||
Exit 1
|
||||
|
Loading…
x
Reference in New Issue
Block a user