From e2a73924ccedf27ed14f07012affa930e1ccdcef Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 21 Feb 2021 12:34:10 -0500 Subject: [PATCH 1/2] Add support for -Zunpretty=hir Co-authored-by: Camelid --- ui/frontend/BuildMenu.tsx | 15 ++++++++++++- ui/frontend/Output.tsx | 8 ++++++- ui/frontend/actions.ts | 30 +++++++++++++++++++++++++ ui/frontend/reducers/output/hir.ts | 33 ++++++++++++++++++++++++++++ ui/frontend/reducers/output/index.ts | 4 +++- ui/frontend/reducers/output/meta.ts | 3 +++ ui/frontend/selectors/index.ts | 6 ++++- ui/frontend/types.ts | 2 ++ ui/src/main.rs | 1 + ui/src/sandbox.rs | 14 +++++++++++- 10 files changed, 111 insertions(+), 5 deletions(-) create mode 100644 ui/frontend/reducers/output/hir.ts diff --git a/ui/frontend/BuildMenu.tsx b/ui/frontend/BuildMenu.tsx index 10f63ae6f..9a4ea349a 100644 --- a/ui/frontend/BuildMenu.tsx +++ b/ui/frontend/BuildMenu.tsx @@ -24,12 +24,14 @@ const useDispatchAndClose = (action: () => void, close: () => void) => { } const BuildMenu: React.SFC = props => { + const isHirAvailable = useSelector(selectors.isHirAvailable); const isWasmAvailable = useSelector(selectors.isWasmAvailable); const compile = useDispatchAndClose(actions.performCompile, props.close); const compileToAssembly = useDispatchAndClose(actions.performCompileToAssembly, props.close); const compileToLLVM = useDispatchAndClose(actions.performCompileToLLVM, props.close); const compileToMir = useDispatchAndClose(actions.performCompileToMir, props.close); + const compileToHir = useDispatchAndClose(actions.performCompileToNightlyHir, props.close); const compileToWasm = useDispatchAndClose(actions.performCompileToNightlyWasm, props.close); const execute = useDispatchAndClose(actions.performExecute, props.close); const test = useDispatchAndClose(actions.performTest, props.close); @@ -55,7 +57,11 @@ const BuildMenu: React.SFC = props => { Build and show the resulting LLVM IR, LLVM’s intermediate representation. - Build and show the resulting MIR, Rust’s intermediate representation. + Build and show the resulting MIR, Rust’s control-flow-based intermediate representation. + + + Build and show the resulting HIR, Rust’s syntax-based intermediate representation. + {!isHirAvailable && } Build a WebAssembly module for web browsers, in the .WAT textual representation. @@ -65,6 +71,13 @@ const BuildMenu: React.SFC = props => { ); }; +const HirAside: React.SFC = () => ( +

+ Note: HIR currently requires using the Nightly channel, selecting this + option will switch to Nightly. +

+); + const WasmAside: React.SFC = () => (

Note: WASM currently requires using the Nightly channel, selecting this diff --git a/ui/frontend/Output.tsx b/ui/frontend/Output.tsx index 64d302ff5..ae5535e2d 100644 --- a/ui/frontend/Output.tsx +++ b/ui/frontend/Output.tsx @@ -46,7 +46,7 @@ interface PaneWithCodeProps extends SimplePaneProps { const Output: React.SFC = () => { const somethingToShow = useSelector(selectors.getSomethingToShow); - const { meta: { focus }, execute, format, clippy, miri, macroExpansion, assembly, llvmIr, mir, wasm, gist } = + const { meta: { focus }, execute, format, clippy, miri, macroExpansion, assembly, llvmIr, mir, hir, wasm, gist } = useSelector((state: State) => state.output); const dispatch = useDispatch(); @@ -59,6 +59,7 @@ const Output: React.SFC = () => { const focusAssembly = useCallback(() => dispatch(actions.changeFocus(Focus.Asm)), [dispatch]); const focusLlvmIr = useCallback(() => dispatch(actions.changeFocus(Focus.LlvmIr)), [dispatch]); const focusMir = useCallback(() => dispatch(actions.changeFocus(Focus.Mir)), [dispatch]); + const focusHir = useCallback(() => dispatch(actions.changeFocus(Focus.Hir)), [dispatch]); const focusWasm = useCallback(() => dispatch(actions.changeFocus(Focus.Wasm)), [dispatch]); const focusGist = useCallback(() => dispatch(actions.changeFocus(Focus.Gist)), [dispatch]); @@ -84,6 +85,7 @@ const Output: React.SFC = () => { {focus === Focus.Asm && } {focus === Focus.LlvmIr && } {focus === Focus.Mir && } + {focus === Focus.Hir && } {focus === Focus.Wasm && } {focus === Focus.Gist && } @@ -125,6 +127,10 @@ const Output: React.SFC = () => { label="MIR" onClick={focusMir} tabProps={mir} /> + failure: receiveCompileLlvmIrFailure, }); +const requestCompileHir = () => + createAction(ActionType.CompileHirRequest); + +const receiveCompileHirSuccess = ({ code, stdout, stderr }) => + createAction(ActionType.CompileHirSucceeded, { code, stdout, stderr }); + +const receiveCompileHirFailure = ({ error }) => + createAction(ActionType.CompileHirFailed, { error }); + +const performCompileToHirOnly = () => + performCompileShow('hir', { + request: requestCompileHir, + success: receiveCompileHirSuccess, + failure: receiveCompileHirFailure, + }); + +const performCompileToNightlyHirOnly = (): ThunkAction => dispatch => { + dispatch(changeChannel(Channel.Nightly)); + dispatch(performCompileToHirOnly()); +}; + const requestCompileMir = () => createAction(ActionType.CompileMirRequest); @@ -390,6 +414,7 @@ const PRIMARY_ACTIONS: { [index in PrimaryAction]: () => ThunkAction } = { [PrimaryActionCore.Test]: performTestOnly, [PrimaryActionAuto.Auto]: performAutoOnly, [PrimaryActionCore.LlvmIr]: performCompileToLLVMOnly, + [PrimaryActionCore.Hir]: performCompileToHirOnly, [PrimaryActionCore.Mir]: performCompileToMirOnly, [PrimaryActionCore.Wasm]: performCompileToNightlyWasmOnly, }; @@ -417,6 +442,8 @@ export const performCompileToLLVM = performAndSwitchPrimaryAction(performCompileToLLVMOnly, PrimaryActionCore.LlvmIr); export const performCompileToMir = performAndSwitchPrimaryAction(performCompileToMirOnly, PrimaryActionCore.Mir); +export const performCompileToNightlyHir = + performAndSwitchPrimaryAction(performCompileToNightlyHirOnly, PrimaryActionCore.Hir); export const performCompileToNightlyWasm = performAndSwitchPrimaryAction(performCompileToNightlyWasmOnly, PrimaryActionCore.Wasm); @@ -790,6 +817,9 @@ export type Action = | ReturnType | ReturnType | ReturnType + | ReturnType + | ReturnType + | ReturnType | ReturnType | ReturnType | ReturnType diff --git a/ui/frontend/reducers/output/hir.ts b/ui/frontend/reducers/output/hir.ts new file mode 100644 index 000000000..32db2d7bc --- /dev/null +++ b/ui/frontend/reducers/output/hir.ts @@ -0,0 +1,33 @@ +import { Action, ActionType } from '../../actions'; +import { finish, start } from './sharedStateManagement'; + +const DEFAULT: State = { + requestsInProgress: 0, + code: null, + stdout: null, + stderr: null, + error: null, +}; + +interface State { + requestsInProgress: number; + code?: string; + stdout?: string; + stderr?: string; + error?: string; +} + +export default function hir(state = DEFAULT, action: Action) { + switch (action.type) { + case ActionType.CompileHirRequest: + return start(DEFAULT, state); + case ActionType.CompileHirSucceeded: { + const { code = '', stdout = '', stderr = '' } = action; + return finish(state, { code, stdout, stderr }); + } + case ActionType.CompileHirFailed: + return finish(state, { error: action.error }); + default: + return state; + } +} diff --git a/ui/frontend/reducers/output/index.ts b/ui/frontend/reducers/output/index.ts index 885d48bfc..8942a967a 100644 --- a/ui/frontend/reducers/output/index.ts +++ b/ui/frontend/reducers/output/index.ts @@ -5,11 +5,12 @@ import clippy from './clippy'; import execute from './execute'; import format from './format'; import gist from './gist'; +import hir from './hir'; import llvmIr from './llvmIr'; +import macroExpansion from './macroExpansion'; import meta from './meta'; import mir from './mir'; import miri from './miri'; -import macroExpansion from './macroExpansion'; import wasm from './wasm'; const output = combineReducers({ @@ -21,6 +22,7 @@ const output = combineReducers({ assembly, llvmIr, mir, + hir, wasm, execute, gist, diff --git a/ui/frontend/reducers/output/meta.ts b/ui/frontend/reducers/output/meta.ts index 6354d807a..37689c903 100644 --- a/ui/frontend/reducers/output/meta.ts +++ b/ui/frontend/reducers/output/meta.ts @@ -29,6 +29,9 @@ export default function meta(state = DEFAULT, action: Action) { case ActionType.CompileMirRequest: return { ...state, focus: Focus.Mir }; + case ActionType.CompileHirRequest: + return { ...state, focus: Focus.Hir }; + case ActionType.CompileWasmRequest: return { ...state, focus: Focus.Wasm }; diff --git a/ui/frontend/selectors/index.ts b/ui/frontend/selectors/index.ts index 70ae36f1a..90e3e52ef 100644 --- a/ui/frontend/selectors/index.ts +++ b/ui/frontend/selectors/index.ts @@ -71,6 +71,7 @@ const LABELS: { [index in PrimaryActionCore]: string } = { [PrimaryActionCore.Compile]: 'Build', [PrimaryActionCore.Execute]: 'Run', [PrimaryActionCore.LlvmIr]: 'Show LLVM IR', + [PrimaryActionCore.Hir]: 'Show HIR', [PrimaryActionCore.Mir]: 'Show MIR', [PrimaryActionCore.Test]: 'Test', [PrimaryActionCore.Wasm]: 'Show WASM', @@ -102,9 +103,11 @@ export const miriVersionDetailsText = createSelector([getMiri], versionDetails); const editionSelector = (state: State) => state.configuration.edition; -export const isWasmAvailable = (state: State) => ( +export const isNightlyChannel = (state: State) => ( state.configuration.channel === Channel.Nightly ); +export const isWasmAvailable = isNightlyChannel; +export const isHirAvailable = isNightlyChannel; export const getModeLabel = (state: State) => { const { configuration: { mode } } = state; @@ -142,6 +145,7 @@ const getOutputs = (state: State) => [ state.output.gist, state.output.llvmIr, state.output.mir, + state.output.hir, state.output.miri, state.output.macroExpansion, state.output.wasm, diff --git a/ui/frontend/types.ts b/ui/frontend/types.ts index 2f8e7cc68..a21518986 100644 --- a/ui/frontend/types.ts +++ b/ui/frontend/types.ts @@ -74,6 +74,7 @@ export enum PrimaryActionCore { Compile = 'compile', Execute = 'execute', LlvmIr = 'llvm-ir', + Hir = 'hir', Mir = 'mir', Test = 'test', Wasm = 'wasm', @@ -108,6 +109,7 @@ export enum Focus { MacroExpansion = 'macro-expansion', LlvmIr = 'llvm-ir', Mir = 'mir', + Hir = 'hir', Wasm = 'wasm', Asm = 'asm', Execute = 'execute', diff --git a/ui/src/main.rs b/ui/src/main.rs index 004b30a75..2421bb8f2 100644 --- a/ui/src/main.rs +++ b/ui/src/main.rs @@ -934,6 +934,7 @@ fn parse_target(s: &str) -> Result { sandbox::ProcessAssembly::Filter), "llvm-ir" => sandbox::CompileTarget::LlvmIr, "mir" => sandbox::CompileTarget::Mir, + "hir" => sandbox::CompileTarget::Hir, "wasm" => sandbox::CompileTarget::Wasm, value => InvalidTarget { value }.fail()?, }) diff --git a/ui/src/sandbox.rs b/ui/src/sandbox.rs index 153ccf5f3..2b529d088 100644 --- a/ui/src/sandbox.rs +++ b/ui/src/sandbox.rs @@ -169,6 +169,8 @@ impl Sandbox { if process == ProcessAssembly::Filter { code = super::asm_cleanup::filter_asm(&code); } + } else if CompileTarget::Hir == req.target { + // TODO: Run rustfmt on the generated HIR. } Ok(CompileResponse { @@ -479,7 +481,13 @@ fn build_execution_command(target: Option, channel: Channel, mode } if let Some(target) = target { - cmd.extend(&["--", "-o", "/playground-result/compilation"]); + cmd.extend(&["--", "-o"]); + if target == Hir { + // -Zunpretty=hir only emits the HIR, not the binary itself + cmd.push("/playground-result/compilation.hir"); + } else { + cmd.push("/playground-result/compilation"); + } match target { Assembly(flavor, _, _) => { @@ -501,6 +509,7 @@ fn build_execution_command(target: Option, channel: Channel, mode }, LlvmIr => cmd.push("--emit=llvm-ir"), Mir => cmd.push("--emit=mir"), + Hir => cmd.push("-Zunpretty=hir"), Wasm => { /* handled by cargo-wasm wrapper */ }, } } @@ -612,6 +621,7 @@ pub enum CompileTarget { Assembly(AssemblyFlavor, DemangleAssembly, ProcessAssembly), LlvmIr, Mir, + Hir, Wasm, } @@ -621,6 +631,7 @@ impl CompileTarget { CompileTarget::Assembly(_, _, _) => "s", CompileTarget::LlvmIr => "ll", CompileTarget::Mir => "mir", + CompileTarget::Hir => "hir", CompileTarget::Wasm => "wat", }; OsStr::new(ext) @@ -635,6 +646,7 @@ impl fmt::Display for CompileTarget { Assembly(_, _, _) => "assembly".fmt(f), LlvmIr => "LLVM IR".fmt(f), Mir => "Rust MIR".fmt(f), + Hir => "Rust HIR".fmt(f), Wasm => "WebAssembly".fmt(f), } } From 6f5a835c9af3ba406dbe93b703818111fc9b6788 Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Sun, 14 Mar 2021 21:36:59 -0400 Subject: [PATCH 2/2] Add an integration test for HIR output --- tests/spec/features/compilation_targets_spec.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/spec/features/compilation_targets_spec.rb b/tests/spec/features/compilation_targets_spec.rb index 5d358ed88..8c07e70f3 100644 --- a/tests/spec/features/compilation_targets_spec.rb +++ b/tests/spec/features/compilation_targets_spec.rb @@ -95,6 +95,18 @@ end end + scenario "compiling to HIR" do + editor.set <<~EOF + fn demo() -> impl std::fmt::Display { 42 } + EOF + + in_build_menu { click_on("HIR") } + + within('.output-result') do + expect(page).to have_content 'fn demo() -> /*impl Trait*/ { 42 }' + end + end + scenario "compiling to WebAssembly" do in_build_menu { click_on("WASM") }