Skip to content

sema: Improvements to union and struct layout resolution to solve a false-positive circular dependency error - #17490

Closed
kcbanner wants to merge 1 commit into
ziglang:masterfrom
kcbanner:container_circular_dependency
Closed

sema: Improvements to union and struct layout resolution to solve a false-positive circular dependency error#17490
kcbanner wants to merge 1 commit into
ziglang:masterfrom
kcbanner:container_circular_dependency

Conversation

@kcbanner

@kcbannerkcbanner commented Oct 12, 2023

Copy link
Copy Markdown
Contributor

Fixes#17287
Fixes#17533

These changes bring unions up to speed with structs in terms of alignment and size resolution. The main goal of this PR was to resolve the circular dependency error you used to get when doing something like this:

constUnionInner=externstruct {
outer: UnionOuter=std.mem.zeroes(UnionOuter),
};
constUnion=externunion {
outer: ?*UnionOuter,
inner: ?*UnionInner,
};
constUnionOuter=externstruct {
u: Union=std.mem.zeroes(Union),
};
17287.zig:8:22: error: union '17287.Union' depends on itself
const Union = extern union {
~~~~~~~^~~~~
17287.zig:14:5: note: while checking this field
u: Union = std.mem.zeroes(Union),
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Since the fields are pointer types, there isn't actually a circular dependency here.

Changes:

  • Add resolveUnionAlignment, to resolve a union's alignment only, without triggering layout resolution.
  • Update resolveUnionLayout to cache size, alignment, and padding. abiSizeAdvanced and abiAlignmentAdvanced now use this information instead of computing it each time.
  • Resolve the false-positive circular dependency error when a union or struct uses @typeInfo on itself (such as std.mem.zeroes), when it has a field who's type refers to the containing type through a pointer.

@mlugg

mlugg commented Oct 12, 2023

Copy link
Copy Markdown
Member

I don't understand what the titular feature of this PR is doing. Clearly, in order to determine the ABI size of a union, we must know the size of all of its fields. Determining ABI size is a subset of layout resolution, so to resolve the former without resolving the latter (as is in the title of this PR) would imply that there exists some type whose size we can determine without fully resolving its in-memory layout. This seems contradictory to the whole idea of layout resolution. Do you have an example of such a case? (That is, a case where resolving a type's size requires less information than resolving its layout.)

@kcbanner
kcbannerforce-pushed the container_circular_dependency branch from 93d503c to 428f970CompareOctober 12, 2023 22:54
@kcbannerkcbanner changed the title sema: rework union layout resolution to resolve only the union's layout, instead of recursively resolving all fieldssema: Improvements to union and struct layout resolution to solve a false-positive circular dependency errorOct 12, 2023
@kcbanner

Copy link
Copy Markdown
ContributorAuthor

I don't understand what the titular feature of this PR is doing. Clearly, in order to determine the ABI size of a union, we must know the size of all of its fields. Determining ABI size is a subset of layout resolution, so to resolve the former without resolving the latter (as is in the title of this PR) would imply that there exists some type whose size we can determine without fully resolving its in-memory layout. This seems contradictory to the whole idea of layout resolution. Do you have an example of such a case? (That is, a case where resolving a type's size requires less information than resolving its layout.)

@mlugg Sorry, the original title was poor - it was the commit message of my initial changes before I really understood what was going on. I've updated the title and description now.

@kcbanner
kcbannerforce-pushed the container_circular_dependency branch 3 times, most recently from 88489bb to 981e001CompareOctober 13, 2023 05:32
- Add resolveUnionAlignment, to resolve a union's alignment only, without triggering layout resolution
- Update resolveUnionLayout to cache size, alignment, and padding
- Resolve a false-positive circular dependency error when a union or struct uses @typeinfo on itself (such as std.mem.zeroes)
@kcbanner
kcbannerforce-pushed the container_circular_dependency branch from 981e001 to 3a89324CompareOctober 13, 2023 05:32
@kcbanner
kcbanner marked this pull request as ready for review October 13, 2023 05:33
@kcbanner

Copy link
Copy Markdown
ContributorAuthor

For reviewer's reference (and as a justification for CircularComptimeRequirementCheck or something similar) this is stack of the error: union 'container_circular_dependency.Union' depends on itself error if you comment out all the return error.CircularComptimeRequirementCheck; that I've added.

zig.exe;resolveUnionLayout();7FF60D07BB90;6FBB90
zig.exe;resolveTypeLayout();7FF60CE08456;488456
zig.exe;typeAbiSize();7FF60D4BBC94;B3BC94
zig.exe;resolveStructLayout();7FF60D07A6D5;6FA6D5
zig.exe;resolveTypeLayout();7FF60CE083D2;4883D2
zig.exe;zirTypeInfo();7FF60D42D3E8;AAD3E8
zig.exe;analyzeBodyInner();7FF60D06A4F2;6EA4F2
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;analyzeBodyInner();7FF60D07904C;6F904C
zig.exe;analyzeBody();7FF60D38DD7F;A0DD7F
zig.exe;analyzeCall();7FF60D930E41;FB0E41
zig.exe;zirCall__anon_161264();7FF60D3F2E77;A72E77
zig.exe;analyzeBodyInner();7FF60D066F53;6E6F53
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;resolveBody();7FF60D9278CD;FA78CD
zig.exe;semaStructFields();7FF60D9F1257;1071257
zig.exe;resolveTypeFieldsStruct();7FF60D4C65E2;B465E2
zig.exe;comptimeOnlyAdvanced();7FF60D07EC26;6FEC26
zig.exe;comptimeOnlyAdvanced();7FF60D07E329;6FE329
zig.exe;typeRequiresComptime();7FF60CDF77DD;4777DD
zig.exe;hasRuntimeBitsAdvanced();7FF60D080C24;700C24
zig.exe;typeHasRuntimeBits();7FF60CDFAC6C;47AC6C
zig.exe;unionFieldHasRuntimeBits();7FF60D4C0344;B40344
zig.exe;resolveUnionLayout();7FF60D07BDB1;6FBDB1
zig.exe;resolveTypeLayout();7FF60CE08456;488456
zig.exe;zirTypeInfo();7FF60D42A75E;AAA75E
zig.exe;analyzeBodyInner();7FF60D06A4F2;6EA4F2
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;analyzeBodyInner();7FF60D07904C;6F904C
zig.exe;analyzeBody();7FF60D38DD7F;A0DD7F
zig.exe;analyzeCall();7FF60D930E41;FB0E41
zig.exe;zirCall__anon_161264();7FF60D3F2E77;A72E77
zig.exe;analyzeBodyInner();7FF60D066F53;6E6F53
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;resolveBody();7FF60D9278CD;FA78CD
zig.exe;semaStructFields();7FF60D9F1257;1071257
zig.exe;resolveTypeFieldsStruct();7FF60D4C65E2;B465E2
zig.exe;comptimeOnlyAdvanced();7FF60D07EC26;6FEC26
zig.exe;typeRequiresComptime();7FF60CDF77DD;4777DD
zig.exe;validateVarType();7FF60D901A07;F81A07
zig.exe;zirAllocMut();7FF60D3E1FFB;A61FFB
zig.exe;analyzeBodyInner();7FF60D065DD4;6E5DD4
zig.exe;resolveBlockBody();7FF60D9E509A;106509A
zig.exe;zirBlock();7FF60D4BB201;B3B201
zig.exe;analyzeBodyInner();7FF60D078DFE;6F8DFE
zig.exe;analyzeBody();7FF60D38DD7F;A0DD7F
zig.exe;analyzeFnBody();7FF60D045507;6C5507
zig.exe;ensureFuncBodyAnalyzed();7FF60CDF0FA4;470FA4
zig.exe;processOneJob();7FF60CDEEFBD;46EFBD
zig.exe;performAllTheWork();7FF60CC34098;2B4098
zig.exe;update();7FF60CC2F1F9;2AF1F9
zig.exe;updateModule();7FF60CC5DA65;2DDA65
zig.exe;buildOutputType();7FF60CC809E6;3009E6
zig.exe;mainArgs();7FF60CA9D8F1;11D8F1
zig.exe;main();7FF60CA9B16E;11B16E
zig.exe;main();7FF60CA9AE6A;11AE6A
zig.exe;__tmainCRTStartup();7FF60EFB56A6;26356A6
zig.exe;mainCRTStartup();7FF60EFB570C;263570C

@kcbanner

kcbanner commented Oct 21, 2023

Copy link
Copy Markdown
ContributorAuthor

After talking with @mlugg, I've decided to extra just the union alignment portion into #17658, and work on a different way to solve this circular dependency.

mlugg: So I think the best option is to introduce yet another resolution stage, where we resolve default inits after field types
mlugg: Here's a simple example of a dodgy case:

const S = struct { x: u32 = @alignOf(S) + 1 };

(The addition here is just to force us to resolve the lazy value)
This in theory is fine, right? We know from the field types that S has alignment 4, so x should have default value 5. However, because we try to resolve the inits at the same time as the field types, we can't know the alignment of S before we attempt to resolve the field init. In this case, it triggers the "guess pointer aligned" code, so S gets alignment 8

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Setting member default values causes false detection of a dependency loop @cImport "union depends on itself" regression

2 participants

@kcbanner@mlugg
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
sema: Improvements to union and struct layout resolution to solve a false-positive circular dependency error by kcbanner · Pull Request #17490 · ziglang/zig · GitHub
Skip to content

sema: Improvements to union and struct layout resolution to solve a false-positive circular dependency error - #17490

Closed
kcbanner wants to merge 1 commit into
ziglang:masterfrom
kcbanner:container_circular_dependency
Closed

sema: Improvements to union and struct layout resolution to solve a false-positive circular dependency error#17490
kcbanner wants to merge 1 commit into
ziglang:masterfrom
kcbanner:container_circular_dependency

Conversation

@kcbanner

@kcbannerkcbanner commented Oct 12, 2023

Copy link
Copy Markdown
Contributor

Fixes#17287
Fixes#17533

These changes bring unions up to speed with structs in terms of alignment and size resolution. The main goal of this PR was to resolve the circular dependency error you used to get when doing something like this:

constUnionInner=externstruct {
outer: UnionOuter=std.mem.zeroes(UnionOuter),
};
constUnion=externunion {
outer: ?*UnionOuter,
inner: ?*UnionInner,
};
constUnionOuter=externstruct {
u: Union=std.mem.zeroes(Union),
};
17287.zig:8:22: error: union '17287.Union' depends on itself
const Union = extern union {
~~~~~~~^~~~~
17287.zig:14:5: note: while checking this field
u: Union = std.mem.zeroes(Union),
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Since the fields are pointer types, there isn't actually a circular dependency here.

Changes:

  • Add resolveUnionAlignment, to resolve a union's alignment only, without triggering layout resolution.
  • Update resolveUnionLayout to cache size, alignment, and padding. abiSizeAdvanced and abiAlignmentAdvanced now use this information instead of computing it each time.
  • Resolve the false-positive circular dependency error when a union or struct uses @typeInfo on itself (such as std.mem.zeroes), when it has a field who's type refers to the containing type through a pointer.

@mlugg

mlugg commented Oct 12, 2023

Copy link
Copy Markdown
Member

I don't understand what the titular feature of this PR is doing. Clearly, in order to determine the ABI size of a union, we must know the size of all of its fields. Determining ABI size is a subset of layout resolution, so to resolve the former without resolving the latter (as is in the title of this PR) would imply that there exists some type whose size we can determine without fully resolving its in-memory layout. This seems contradictory to the whole idea of layout resolution. Do you have an example of such a case? (That is, a case where resolving a type's size requires less information than resolving its layout.)

@kcbanner
kcbannerforce-pushed the container_circular_dependency branch from 93d503c to 428f970CompareOctober 12, 2023 22:54
@kcbannerkcbanner changed the title sema: rework union layout resolution to resolve only the union's layout, instead of recursively resolving all fieldssema: Improvements to union and struct layout resolution to solve a false-positive circular dependency errorOct 12, 2023
@kcbanner

Copy link
Copy Markdown
ContributorAuthor

I don't understand what the titular feature of this PR is doing. Clearly, in order to determine the ABI size of a union, we must know the size of all of its fields. Determining ABI size is a subset of layout resolution, so to resolve the former without resolving the latter (as is in the title of this PR) would imply that there exists some type whose size we can determine without fully resolving its in-memory layout. This seems contradictory to the whole idea of layout resolution. Do you have an example of such a case? (That is, a case where resolving a type's size requires less information than resolving its layout.)

@mlugg Sorry, the original title was poor - it was the commit message of my initial changes before I really understood what was going on. I've updated the title and description now.

@kcbanner
kcbannerforce-pushed the container_circular_dependency branch 3 times, most recently from 88489bb to 981e001CompareOctober 13, 2023 05:32
- Add resolveUnionAlignment, to resolve a union's alignment only, without triggering layout resolution
- Update resolveUnionLayout to cache size, alignment, and padding
- Resolve a false-positive circular dependency error when a union or struct uses @typeinfo on itself (such as std.mem.zeroes)
@kcbanner
kcbannerforce-pushed the container_circular_dependency branch from 981e001 to 3a89324CompareOctober 13, 2023 05:32
@kcbanner
kcbanner marked this pull request as ready for review October 13, 2023 05:33
@kcbanner

Copy link
Copy Markdown
ContributorAuthor

For reviewer's reference (and as a justification for CircularComptimeRequirementCheck or something similar) this is stack of the error: union 'container_circular_dependency.Union' depends on itself error if you comment out all the return error.CircularComptimeRequirementCheck; that I've added.

zig.exe;resolveUnionLayout();7FF60D07BB90;6FBB90
zig.exe;resolveTypeLayout();7FF60CE08456;488456
zig.exe;typeAbiSize();7FF60D4BBC94;B3BC94
zig.exe;resolveStructLayout();7FF60D07A6D5;6FA6D5
zig.exe;resolveTypeLayout();7FF60CE083D2;4883D2
zig.exe;zirTypeInfo();7FF60D42D3E8;AAD3E8
zig.exe;analyzeBodyInner();7FF60D06A4F2;6EA4F2
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;analyzeBodyInner();7FF60D07904C;6F904C
zig.exe;analyzeBody();7FF60D38DD7F;A0DD7F
zig.exe;analyzeCall();7FF60D930E41;FB0E41
zig.exe;zirCall__anon_161264();7FF60D3F2E77;A72E77
zig.exe;analyzeBodyInner();7FF60D066F53;6E6F53
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;resolveBody();7FF60D9278CD;FA78CD
zig.exe;semaStructFields();7FF60D9F1257;1071257
zig.exe;resolveTypeFieldsStruct();7FF60D4C65E2;B465E2
zig.exe;comptimeOnlyAdvanced();7FF60D07EC26;6FEC26
zig.exe;comptimeOnlyAdvanced();7FF60D07E329;6FE329
zig.exe;typeRequiresComptime();7FF60CDF77DD;4777DD
zig.exe;hasRuntimeBitsAdvanced();7FF60D080C24;700C24
zig.exe;typeHasRuntimeBits();7FF60CDFAC6C;47AC6C
zig.exe;unionFieldHasRuntimeBits();7FF60D4C0344;B40344
zig.exe;resolveUnionLayout();7FF60D07BDB1;6FBDB1
zig.exe;resolveTypeLayout();7FF60CE08456;488456
zig.exe;zirTypeInfo();7FF60D42A75E;AAA75E
zig.exe;analyzeBodyInner();7FF60D06A4F2;6EA4F2
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;analyzeBodyInner();7FF60D07904C;6F904C
zig.exe;analyzeBody();7FF60D38DD7F;A0DD7F
zig.exe;analyzeCall();7FF60D930E41;FB0E41
zig.exe;zirCall__anon_161264();7FF60D3F2E77;A72E77
zig.exe;analyzeBodyInner();7FF60D066F53;6E6F53
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;resolveBody();7FF60D9278CD;FA78CD
zig.exe;semaStructFields();7FF60D9F1257;1071257
zig.exe;resolveTypeFieldsStruct();7FF60D4C65E2;B465E2
zig.exe;comptimeOnlyAdvanced();7FF60D07EC26;6FEC26
zig.exe;typeRequiresComptime();7FF60CDF77DD;4777DD
zig.exe;validateVarType();7FF60D901A07;F81A07
zig.exe;zirAllocMut();7FF60D3E1FFB;A61FFB
zig.exe;analyzeBodyInner();7FF60D065DD4;6E5DD4
zig.exe;resolveBlockBody();7FF60D9E509A;106509A
zig.exe;zirBlock();7FF60D4BB201;B3B201
zig.exe;analyzeBodyInner();7FF60D078DFE;6F8DFE
zig.exe;analyzeBody();7FF60D38DD7F;A0DD7F
zig.exe;analyzeFnBody();7FF60D045507;6C5507
zig.exe;ensureFuncBodyAnalyzed();7FF60CDF0FA4;470FA4
zig.exe;processOneJob();7FF60CDEEFBD;46EFBD
zig.exe;performAllTheWork();7FF60CC34098;2B4098
zig.exe;update();7FF60CC2F1F9;2AF1F9
zig.exe;updateModule();7FF60CC5DA65;2DDA65
zig.exe;buildOutputType();7FF60CC809E6;3009E6
zig.exe;mainArgs();7FF60CA9D8F1;11D8F1
zig.exe;main();7FF60CA9B16E;11B16E
zig.exe;main();7FF60CA9AE6A;11AE6A
zig.exe;__tmainCRTStartup();7FF60EFB56A6;26356A6
zig.exe;mainCRTStartup();7FF60EFB570C;263570C

@kcbanner

kcbanner commented Oct 21, 2023

Copy link
Copy Markdown
ContributorAuthor

After talking with @mlugg, I've decided to extra just the union alignment portion into #17658, and work on a different way to solve this circular dependency.

mlugg: So I think the best option is to introduce yet another resolution stage, where we resolve default inits after field types
mlugg: Here's a simple example of a dodgy case:

const S = struct { x: u32 = @alignOf(S) + 1 };

(The addition here is just to force us to resolve the lazy value)
This in theory is fine, right? We know from the field types that S has alignment 4, so x should have default value 5. However, because we try to resolve the inits at the same time as the field types, we can't know the alignment of S before we attempt to resolve the field init. In this case, it triggers the "guess pointer aligned" code, so S gets alignment 8

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Setting member default values causes false detection of a dependency loop @cImport "union depends on itself" regression

2 participants

@kcbanner@mlugg
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' sema: Improvements to union and struct layout resolution to solve a false-positive circular dependency error by kcbanner · Pull Request #17490 · ziglang/zig · GitHub
Skip to content

sema: Improvements to union and struct layout resolution to solve a false-positive circular dependency error - #17490

Closed
kcbanner wants to merge 1 commit into
ziglang:masterfrom
kcbanner:container_circular_dependency
Closed

sema: Improvements to union and struct layout resolution to solve a false-positive circular dependency error#17490
kcbanner wants to merge 1 commit into
ziglang:masterfrom
kcbanner:container_circular_dependency

Conversation

@kcbanner

@kcbannerkcbanner commented Oct 12, 2023

Copy link
Copy Markdown
Contributor

Fixes#17287
Fixes#17533

These changes bring unions up to speed with structs in terms of alignment and size resolution. The main goal of this PR was to resolve the circular dependency error you used to get when doing something like this:

constUnionInner=externstruct {
outer: UnionOuter=std.mem.zeroes(UnionOuter),
};
constUnion=externunion {
outer: ?*UnionOuter,
inner: ?*UnionInner,
};
constUnionOuter=externstruct {
u: Union=std.mem.zeroes(Union),
};
17287.zig:8:22: error: union '17287.Union' depends on itself
const Union = extern union {
~~~~~~~^~~~~
17287.zig:14:5: note: while checking this field
u: Union = std.mem.zeroes(Union),
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Since the fields are pointer types, there isn't actually a circular dependency here.

Changes:

  • Add resolveUnionAlignment, to resolve a union's alignment only, without triggering layout resolution.
  • Update resolveUnionLayout to cache size, alignment, and padding. abiSizeAdvanced and abiAlignmentAdvanced now use this information instead of computing it each time.
  • Resolve the false-positive circular dependency error when a union or struct uses @typeInfo on itself (such as std.mem.zeroes), when it has a field who's type refers to the containing type through a pointer.

@mlugg

mlugg commented Oct 12, 2023

Copy link
Copy Markdown
Member

I don't understand what the titular feature of this PR is doing. Clearly, in order to determine the ABI size of a union, we must know the size of all of its fields. Determining ABI size is a subset of layout resolution, so to resolve the former without resolving the latter (as is in the title of this PR) would imply that there exists some type whose size we can determine without fully resolving its in-memory layout. This seems contradictory to the whole idea of layout resolution. Do you have an example of such a case? (That is, a case where resolving a type's size requires less information than resolving its layout.)

@kcbanner
kcbannerforce-pushed the container_circular_dependency branch from 93d503c to 428f970CompareOctober 12, 2023 22:54
@kcbannerkcbanner changed the title sema: rework union layout resolution to resolve only the union's layout, instead of recursively resolving all fieldssema: Improvements to union and struct layout resolution to solve a false-positive circular dependency errorOct 12, 2023
@kcbanner

Copy link
Copy Markdown
ContributorAuthor

I don't understand what the titular feature of this PR is doing. Clearly, in order to determine the ABI size of a union, we must know the size of all of its fields. Determining ABI size is a subset of layout resolution, so to resolve the former without resolving the latter (as is in the title of this PR) would imply that there exists some type whose size we can determine without fully resolving its in-memory layout. This seems contradictory to the whole idea of layout resolution. Do you have an example of such a case? (That is, a case where resolving a type's size requires less information than resolving its layout.)

@mlugg Sorry, the original title was poor - it was the commit message of my initial changes before I really understood what was going on. I've updated the title and description now.

@kcbanner
kcbannerforce-pushed the container_circular_dependency branch 3 times, most recently from 88489bb to 981e001CompareOctober 13, 2023 05:32
- Add resolveUnionAlignment, to resolve a union's alignment only, without triggering layout resolution
- Update resolveUnionLayout to cache size, alignment, and padding
- Resolve a false-positive circular dependency error when a union or struct uses @typeinfo on itself (such as std.mem.zeroes)
@kcbanner
kcbannerforce-pushed the container_circular_dependency branch from 981e001 to 3a89324CompareOctober 13, 2023 05:32
@kcbanner
kcbanner marked this pull request as ready for review October 13, 2023 05:33
@kcbanner

Copy link
Copy Markdown
ContributorAuthor

For reviewer's reference (and as a justification for CircularComptimeRequirementCheck or something similar) this is stack of the error: union 'container_circular_dependency.Union' depends on itself error if you comment out all the return error.CircularComptimeRequirementCheck; that I've added.

zig.exe;resolveUnionLayout();7FF60D07BB90;6FBB90
zig.exe;resolveTypeLayout();7FF60CE08456;488456
zig.exe;typeAbiSize();7FF60D4BBC94;B3BC94
zig.exe;resolveStructLayout();7FF60D07A6D5;6FA6D5
zig.exe;resolveTypeLayout();7FF60CE083D2;4883D2
zig.exe;zirTypeInfo();7FF60D42D3E8;AAD3E8
zig.exe;analyzeBodyInner();7FF60D06A4F2;6EA4F2
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;analyzeBodyInner();7FF60D07904C;6F904C
zig.exe;analyzeBody();7FF60D38DD7F;A0DD7F
zig.exe;analyzeCall();7FF60D930E41;FB0E41
zig.exe;zirCall__anon_161264();7FF60D3F2E77;A72E77
zig.exe;analyzeBodyInner();7FF60D066F53;6E6F53
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;resolveBody();7FF60D9278CD;FA78CD
zig.exe;semaStructFields();7FF60D9F1257;1071257
zig.exe;resolveTypeFieldsStruct();7FF60D4C65E2;B465E2
zig.exe;comptimeOnlyAdvanced();7FF60D07EC26;6FEC26
zig.exe;comptimeOnlyAdvanced();7FF60D07E329;6FE329
zig.exe;typeRequiresComptime();7FF60CDF77DD;4777DD
zig.exe;hasRuntimeBitsAdvanced();7FF60D080C24;700C24
zig.exe;typeHasRuntimeBits();7FF60CDFAC6C;47AC6C
zig.exe;unionFieldHasRuntimeBits();7FF60D4C0344;B40344
zig.exe;resolveUnionLayout();7FF60D07BDB1;6FBDB1
zig.exe;resolveTypeLayout();7FF60CE08456;488456
zig.exe;zirTypeInfo();7FF60D42A75E;AAA75E
zig.exe;analyzeBodyInner();7FF60D06A4F2;6EA4F2
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;analyzeBodyInner();7FF60D07904C;6F904C
zig.exe;analyzeBody();7FF60D38DD7F;A0DD7F
zig.exe;analyzeCall();7FF60D930E41;FB0E41
zig.exe;zirCall__anon_161264();7FF60D3F2E77;A72E77
zig.exe;analyzeBodyInner();7FF60D066F53;6E6F53
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;resolveBody();7FF60D9278CD;FA78CD
zig.exe;semaStructFields();7FF60D9F1257;1071257
zig.exe;resolveTypeFieldsStruct();7FF60D4C65E2;B465E2
zig.exe;comptimeOnlyAdvanced();7FF60D07EC26;6FEC26
zig.exe;typeRequiresComptime();7FF60CDF77DD;4777DD
zig.exe;validateVarType();7FF60D901A07;F81A07
zig.exe;zirAllocMut();7FF60D3E1FFB;A61FFB
zig.exe;analyzeBodyInner();7FF60D065DD4;6E5DD4
zig.exe;resolveBlockBody();7FF60D9E509A;106509A
zig.exe;zirBlock();7FF60D4BB201;B3B201
zig.exe;analyzeBodyInner();7FF60D078DFE;6F8DFE
zig.exe;analyzeBody();7FF60D38DD7F;A0DD7F
zig.exe;analyzeFnBody();7FF60D045507;6C5507
zig.exe;ensureFuncBodyAnalyzed();7FF60CDF0FA4;470FA4
zig.exe;processOneJob();7FF60CDEEFBD;46EFBD
zig.exe;performAllTheWork();7FF60CC34098;2B4098
zig.exe;update();7FF60CC2F1F9;2AF1F9
zig.exe;updateModule();7FF60CC5DA65;2DDA65
zig.exe;buildOutputType();7FF60CC809E6;3009E6
zig.exe;mainArgs();7FF60CA9D8F1;11D8F1
zig.exe;main();7FF60CA9B16E;11B16E
zig.exe;main();7FF60CA9AE6A;11AE6A
zig.exe;__tmainCRTStartup();7FF60EFB56A6;26356A6
zig.exe;mainCRTStartup();7FF60EFB570C;263570C

@kcbanner

kcbanner commented Oct 21, 2023

Copy link
Copy Markdown
ContributorAuthor

After talking with @mlugg, I've decided to extra just the union alignment portion into #17658, and work on a different way to solve this circular dependency.

mlugg: So I think the best option is to introduce yet another resolution stage, where we resolve default inits after field types
mlugg: Here's a simple example of a dodgy case:

const S = struct { x: u32 = @alignOf(S) + 1 };

(The addition here is just to force us to resolve the lazy value)
This in theory is fine, right? We know from the field types that S has alignment 4, so x should have default value 5. However, because we try to resolve the inits at the same time as the field types, we can't know the alignment of S before we attempt to resolve the field init. In this case, it triggers the "guess pointer aligned" code, so S gets alignment 8

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Setting member default values causes false detection of a dependency loop @cImport "union depends on itself" regression

2 participants

@kcbanner@mlugg
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' sema: Improvements to union and struct layout resolution to solve a false-positive circular dependency error by kcbanner · Pull Request #17490 · ziglang/zig · GitHub
Skip to content

sema: Improvements to union and struct layout resolution to solve a false-positive circular dependency error - #17490

Closed
kcbanner wants to merge 1 commit into
ziglang:masterfrom
kcbanner:container_circular_dependency
Closed

sema: Improvements to union and struct layout resolution to solve a false-positive circular dependency error#17490
kcbanner wants to merge 1 commit into
ziglang:masterfrom
kcbanner:container_circular_dependency

Conversation

@kcbanner

@kcbannerkcbanner commented Oct 12, 2023

Copy link
Copy Markdown
Contributor

Fixes#17287
Fixes#17533

These changes bring unions up to speed with structs in terms of alignment and size resolution. The main goal of this PR was to resolve the circular dependency error you used to get when doing something like this:

constUnionInner=externstruct {
outer: UnionOuter=std.mem.zeroes(UnionOuter),
};
constUnion=externunion {
outer: ?*UnionOuter,
inner: ?*UnionInner,
};
constUnionOuter=externstruct {
u: Union=std.mem.zeroes(Union),
};
17287.zig:8:22: error: union '17287.Union' depends on itself
const Union = extern union {
~~~~~~~^~~~~
17287.zig:14:5: note: while checking this field
u: Union = std.mem.zeroes(Union),
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Since the fields are pointer types, there isn't actually a circular dependency here.

Changes:

  • Add resolveUnionAlignment, to resolve a union's alignment only, without triggering layout resolution.
  • Update resolveUnionLayout to cache size, alignment, and padding. abiSizeAdvanced and abiAlignmentAdvanced now use this information instead of computing it each time.
  • Resolve the false-positive circular dependency error when a union or struct uses @typeInfo on itself (such as std.mem.zeroes), when it has a field who's type refers to the containing type through a pointer.

@mlugg

mlugg commented Oct 12, 2023

Copy link
Copy Markdown
Member

I don't understand what the titular feature of this PR is doing. Clearly, in order to determine the ABI size of a union, we must know the size of all of its fields. Determining ABI size is a subset of layout resolution, so to resolve the former without resolving the latter (as is in the title of this PR) would imply that there exists some type whose size we can determine without fully resolving its in-memory layout. This seems contradictory to the whole idea of layout resolution. Do you have an example of such a case? (That is, a case where resolving a type's size requires less information than resolving its layout.)

@kcbanner
kcbannerforce-pushed the container_circular_dependency branch from 93d503c to 428f970CompareOctober 12, 2023 22:54
@kcbannerkcbanner changed the title sema: rework union layout resolution to resolve only the union's layout, instead of recursively resolving all fieldssema: Improvements to union and struct layout resolution to solve a false-positive circular dependency errorOct 12, 2023
@kcbanner

Copy link
Copy Markdown
ContributorAuthor

I don't understand what the titular feature of this PR is doing. Clearly, in order to determine the ABI size of a union, we must know the size of all of its fields. Determining ABI size is a subset of layout resolution, so to resolve the former without resolving the latter (as is in the title of this PR) would imply that there exists some type whose size we can determine without fully resolving its in-memory layout. This seems contradictory to the whole idea of layout resolution. Do you have an example of such a case? (That is, a case where resolving a type's size requires less information than resolving its layout.)

@mlugg Sorry, the original title was poor - it was the commit message of my initial changes before I really understood what was going on. I've updated the title and description now.

@kcbanner
kcbannerforce-pushed the container_circular_dependency branch 3 times, most recently from 88489bb to 981e001CompareOctober 13, 2023 05:32
- Add resolveUnionAlignment, to resolve a union's alignment only, without triggering layout resolution
- Update resolveUnionLayout to cache size, alignment, and padding
- Resolve a false-positive circular dependency error when a union or struct uses @typeinfo on itself (such as std.mem.zeroes)
@kcbanner
kcbannerforce-pushed the container_circular_dependency branch from 981e001 to 3a89324CompareOctober 13, 2023 05:32
@kcbanner
kcbanner marked this pull request as ready for review October 13, 2023 05:33
@kcbanner

Copy link
Copy Markdown
ContributorAuthor

For reviewer's reference (and as a justification for CircularComptimeRequirementCheck or something similar) this is stack of the error: union 'container_circular_dependency.Union' depends on itself error if you comment out all the return error.CircularComptimeRequirementCheck; that I've added.

zig.exe;resolveUnionLayout();7FF60D07BB90;6FBB90
zig.exe;resolveTypeLayout();7FF60CE08456;488456
zig.exe;typeAbiSize();7FF60D4BBC94;B3BC94
zig.exe;resolveStructLayout();7FF60D07A6D5;6FA6D5
zig.exe;resolveTypeLayout();7FF60CE083D2;4883D2
zig.exe;zirTypeInfo();7FF60D42D3E8;AAD3E8
zig.exe;analyzeBodyInner();7FF60D06A4F2;6EA4F2
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;analyzeBodyInner();7FF60D07904C;6F904C
zig.exe;analyzeBody();7FF60D38DD7F;A0DD7F
zig.exe;analyzeCall();7FF60D930E41;FB0E41
zig.exe;zirCall__anon_161264();7FF60D3F2E77;A72E77
zig.exe;analyzeBodyInner();7FF60D066F53;6E6F53
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;resolveBody();7FF60D9278CD;FA78CD
zig.exe;semaStructFields();7FF60D9F1257;1071257
zig.exe;resolveTypeFieldsStruct();7FF60D4C65E2;B465E2
zig.exe;comptimeOnlyAdvanced();7FF60D07EC26;6FEC26
zig.exe;comptimeOnlyAdvanced();7FF60D07E329;6FE329
zig.exe;typeRequiresComptime();7FF60CDF77DD;4777DD
zig.exe;hasRuntimeBitsAdvanced();7FF60D080C24;700C24
zig.exe;typeHasRuntimeBits();7FF60CDFAC6C;47AC6C
zig.exe;unionFieldHasRuntimeBits();7FF60D4C0344;B40344
zig.exe;resolveUnionLayout();7FF60D07BDB1;6FBDB1
zig.exe;resolveTypeLayout();7FF60CE08456;488456
zig.exe;zirTypeInfo();7FF60D42A75E;AAA75E
zig.exe;analyzeBodyInner();7FF60D06A4F2;6EA4F2
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;analyzeBodyInner();7FF60D07904C;6F904C
zig.exe;analyzeBody();7FF60D38DD7F;A0DD7F
zig.exe;analyzeCall();7FF60D930E41;FB0E41
zig.exe;zirCall__anon_161264();7FF60D3F2E77;A72E77
zig.exe;analyzeBodyInner();7FF60D066F53;6E6F53
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;resolveBody();7FF60D9278CD;FA78CD
zig.exe;semaStructFields();7FF60D9F1257;1071257
zig.exe;resolveTypeFieldsStruct();7FF60D4C65E2;B465E2
zig.exe;comptimeOnlyAdvanced();7FF60D07EC26;6FEC26
zig.exe;typeRequiresComptime();7FF60CDF77DD;4777DD
zig.exe;validateVarType();7FF60D901A07;F81A07
zig.exe;zirAllocMut();7FF60D3E1FFB;A61FFB
zig.exe;analyzeBodyInner();7FF60D065DD4;6E5DD4
zig.exe;resolveBlockBody();7FF60D9E509A;106509A
zig.exe;zirBlock();7FF60D4BB201;B3B201
zig.exe;analyzeBodyInner();7FF60D078DFE;6F8DFE
zig.exe;analyzeBody();7FF60D38DD7F;A0DD7F
zig.exe;analyzeFnBody();7FF60D045507;6C5507
zig.exe;ensureFuncBodyAnalyzed();7FF60CDF0FA4;470FA4
zig.exe;processOneJob();7FF60CDEEFBD;46EFBD
zig.exe;performAllTheWork();7FF60CC34098;2B4098
zig.exe;update();7FF60CC2F1F9;2AF1F9
zig.exe;updateModule();7FF60CC5DA65;2DDA65
zig.exe;buildOutputType();7FF60CC809E6;3009E6
zig.exe;mainArgs();7FF60CA9D8F1;11D8F1
zig.exe;main();7FF60CA9B16E;11B16E
zig.exe;main();7FF60CA9AE6A;11AE6A
zig.exe;__tmainCRTStartup();7FF60EFB56A6;26356A6
zig.exe;mainCRTStartup();7FF60EFB570C;263570C

@kcbanner

kcbanner commented Oct 21, 2023

Copy link
Copy Markdown
ContributorAuthor

After talking with @mlugg, I've decided to extra just the union alignment portion into #17658, and work on a different way to solve this circular dependency.

mlugg: So I think the best option is to introduce yet another resolution stage, where we resolve default inits after field types
mlugg: Here's a simple example of a dodgy case:

const S = struct { x: u32 = @alignOf(S) + 1 };

(The addition here is just to force us to resolve the lazy value)
This in theory is fine, right? We know from the field types that S has alignment 4, so x should have default value 5. However, because we try to resolve the inits at the same time as the field types, we can't know the alignment of S before we attempt to resolve the field init. In this case, it triggers the "guess pointer aligned" code, so S gets alignment 8

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Setting member default values causes false detection of a dependency loop @cImport "union depends on itself" regression

2 participants

@kcbanner@mlugg
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' sema: Improvements to union and struct layout resolution to solve a false-positive circular dependency error by kcbanner · Pull Request #17490 · ziglang/zig · GitHub
Skip to content

sema: Improvements to union and struct layout resolution to solve a false-positive circular dependency error - #17490

Closed
kcbanner wants to merge 1 commit into
ziglang:masterfrom
kcbanner:container_circular_dependency
Closed

sema: Improvements to union and struct layout resolution to solve a false-positive circular dependency error#17490
kcbanner wants to merge 1 commit into
ziglang:masterfrom
kcbanner:container_circular_dependency

Conversation

@kcbanner

@kcbannerkcbanner commented Oct 12, 2023

Copy link
Copy Markdown
Contributor

Fixes#17287
Fixes#17533

These changes bring unions up to speed with structs in terms of alignment and size resolution. The main goal of this PR was to resolve the circular dependency error you used to get when doing something like this:

constUnionInner=externstruct {
outer: UnionOuter=std.mem.zeroes(UnionOuter),
};
constUnion=externunion {
outer: ?*UnionOuter,
inner: ?*UnionInner,
};
constUnionOuter=externstruct {
u: Union=std.mem.zeroes(Union),
};
17287.zig:8:22: error: union '17287.Union' depends on itself
const Union = extern union {
~~~~~~~^~~~~
17287.zig:14:5: note: while checking this field
u: Union = std.mem.zeroes(Union),
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Since the fields are pointer types, there isn't actually a circular dependency here.

Changes:

  • Add resolveUnionAlignment, to resolve a union's alignment only, without triggering layout resolution.
  • Update resolveUnionLayout to cache size, alignment, and padding. abiSizeAdvanced and abiAlignmentAdvanced now use this information instead of computing it each time.
  • Resolve the false-positive circular dependency error when a union or struct uses @typeInfo on itself (such as std.mem.zeroes), when it has a field who's type refers to the containing type through a pointer.

@mlugg

mlugg commented Oct 12, 2023

Copy link
Copy Markdown
Member

I don't understand what the titular feature of this PR is doing. Clearly, in order to determine the ABI size of a union, we must know the size of all of its fields. Determining ABI size is a subset of layout resolution, so to resolve the former without resolving the latter (as is in the title of this PR) would imply that there exists some type whose size we can determine without fully resolving its in-memory layout. This seems contradictory to the whole idea of layout resolution. Do you have an example of such a case? (That is, a case where resolving a type's size requires less information than resolving its layout.)

@kcbanner
kcbannerforce-pushed the container_circular_dependency branch from 93d503c to 428f970CompareOctober 12, 2023 22:54
@kcbannerkcbanner changed the title sema: rework union layout resolution to resolve only the union's layout, instead of recursively resolving all fieldssema: Improvements to union and struct layout resolution to solve a false-positive circular dependency errorOct 12, 2023
@kcbanner

Copy link
Copy Markdown
ContributorAuthor

I don't understand what the titular feature of this PR is doing. Clearly, in order to determine the ABI size of a union, we must know the size of all of its fields. Determining ABI size is a subset of layout resolution, so to resolve the former without resolving the latter (as is in the title of this PR) would imply that there exists some type whose size we can determine without fully resolving its in-memory layout. This seems contradictory to the whole idea of layout resolution. Do you have an example of such a case? (That is, a case where resolving a type's size requires less information than resolving its layout.)

@mlugg Sorry, the original title was poor - it was the commit message of my initial changes before I really understood what was going on. I've updated the title and description now.

@kcbanner
kcbannerforce-pushed the container_circular_dependency branch 3 times, most recently from 88489bb to 981e001CompareOctober 13, 2023 05:32
- Add resolveUnionAlignment, to resolve a union's alignment only, without triggering layout resolution
- Update resolveUnionLayout to cache size, alignment, and padding
- Resolve a false-positive circular dependency error when a union or struct uses @typeinfo on itself (such as std.mem.zeroes)
@kcbanner
kcbannerforce-pushed the container_circular_dependency branch from 981e001 to 3a89324CompareOctober 13, 2023 05:32
@kcbanner
kcbanner marked this pull request as ready for review October 13, 2023 05:33
@kcbanner

Copy link
Copy Markdown
ContributorAuthor

For reviewer's reference (and as a justification for CircularComptimeRequirementCheck or something similar) this is stack of the error: union 'container_circular_dependency.Union' depends on itself error if you comment out all the return error.CircularComptimeRequirementCheck; that I've added.

zig.exe;resolveUnionLayout();7FF60D07BB90;6FBB90
zig.exe;resolveTypeLayout();7FF60CE08456;488456
zig.exe;typeAbiSize();7FF60D4BBC94;B3BC94
zig.exe;resolveStructLayout();7FF60D07A6D5;6FA6D5
zig.exe;resolveTypeLayout();7FF60CE083D2;4883D2
zig.exe;zirTypeInfo();7FF60D42D3E8;AAD3E8
zig.exe;analyzeBodyInner();7FF60D06A4F2;6EA4F2
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;analyzeBodyInner();7FF60D07904C;6F904C
zig.exe;analyzeBody();7FF60D38DD7F;A0DD7F
zig.exe;analyzeCall();7FF60D930E41;FB0E41
zig.exe;zirCall__anon_161264();7FF60D3F2E77;A72E77
zig.exe;analyzeBodyInner();7FF60D066F53;6E6F53
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;resolveBody();7FF60D9278CD;FA78CD
zig.exe;semaStructFields();7FF60D9F1257;1071257
zig.exe;resolveTypeFieldsStruct();7FF60D4C65E2;B465E2
zig.exe;comptimeOnlyAdvanced();7FF60D07EC26;6FEC26
zig.exe;comptimeOnlyAdvanced();7FF60D07E329;6FE329
zig.exe;typeRequiresComptime();7FF60CDF77DD;4777DD
zig.exe;hasRuntimeBitsAdvanced();7FF60D080C24;700C24
zig.exe;typeHasRuntimeBits();7FF60CDFAC6C;47AC6C
zig.exe;unionFieldHasRuntimeBits();7FF60D4C0344;B40344
zig.exe;resolveUnionLayout();7FF60D07BDB1;6FBDB1
zig.exe;resolveTypeLayout();7FF60CE08456;488456
zig.exe;zirTypeInfo();7FF60D42A75E;AAA75E
zig.exe;analyzeBodyInner();7FF60D06A4F2;6EA4F2
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;analyzeBodyInner();7FF60D07904C;6F904C
zig.exe;analyzeBody();7FF60D38DD7F;A0DD7F
zig.exe;analyzeCall();7FF60D930E41;FB0E41
zig.exe;zirCall__anon_161264();7FF60D3F2E77;A72E77
zig.exe;analyzeBodyInner();7FF60D066F53;6E6F53
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;resolveBody();7FF60D9278CD;FA78CD
zig.exe;semaStructFields();7FF60D9F1257;1071257
zig.exe;resolveTypeFieldsStruct();7FF60D4C65E2;B465E2
zig.exe;comptimeOnlyAdvanced();7FF60D07EC26;6FEC26
zig.exe;typeRequiresComptime();7FF60CDF77DD;4777DD
zig.exe;validateVarType();7FF60D901A07;F81A07
zig.exe;zirAllocMut();7FF60D3E1FFB;A61FFB
zig.exe;analyzeBodyInner();7FF60D065DD4;6E5DD4
zig.exe;resolveBlockBody();7FF60D9E509A;106509A
zig.exe;zirBlock();7FF60D4BB201;B3B201
zig.exe;analyzeBodyInner();7FF60D078DFE;6F8DFE
zig.exe;analyzeBody();7FF60D38DD7F;A0DD7F
zig.exe;analyzeFnBody();7FF60D045507;6C5507
zig.exe;ensureFuncBodyAnalyzed();7FF60CDF0FA4;470FA4
zig.exe;processOneJob();7FF60CDEEFBD;46EFBD
zig.exe;performAllTheWork();7FF60CC34098;2B4098
zig.exe;update();7FF60CC2F1F9;2AF1F9
zig.exe;updateModule();7FF60CC5DA65;2DDA65
zig.exe;buildOutputType();7FF60CC809E6;3009E6
zig.exe;mainArgs();7FF60CA9D8F1;11D8F1
zig.exe;main();7FF60CA9B16E;11B16E
zig.exe;main();7FF60CA9AE6A;11AE6A
zig.exe;__tmainCRTStartup();7FF60EFB56A6;26356A6
zig.exe;mainCRTStartup();7FF60EFB570C;263570C

@kcbanner

kcbanner commented Oct 21, 2023

Copy link
Copy Markdown
ContributorAuthor

After talking with @mlugg, I've decided to extra just the union alignment portion into #17658, and work on a different way to solve this circular dependency.

mlugg: So I think the best option is to introduce yet another resolution stage, where we resolve default inits after field types
mlugg: Here's a simple example of a dodgy case:

const S = struct { x: u32 = @alignOf(S) + 1 };

(The addition here is just to force us to resolve the lazy value)
This in theory is fine, right? We know from the field types that S has alignment 4, so x should have default value 5. However, because we try to resolve the inits at the same time as the field types, we can't know the alignment of S before we attempt to resolve the field init. In this case, it triggers the "guess pointer aligned" code, so S gets alignment 8

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Setting member default values causes false detection of a dependency loop @cImport "union depends on itself" regression

2 participants

@kcbanner@mlugg
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' sema: Improvements to union and struct layout resolution to solve a false-positive circular dependency error by kcbanner · Pull Request #17490 · ziglang/zig · GitHub
Skip to content

sema: Improvements to union and struct layout resolution to solve a false-positive circular dependency error - #17490

Closed
kcbanner wants to merge 1 commit into
ziglang:masterfrom
kcbanner:container_circular_dependency
Closed

sema: Improvements to union and struct layout resolution to solve a false-positive circular dependency error#17490
kcbanner wants to merge 1 commit into
ziglang:masterfrom
kcbanner:container_circular_dependency

Conversation

@kcbanner

@kcbannerkcbanner commented Oct 12, 2023

Copy link
Copy Markdown
Contributor

Fixes#17287
Fixes#17533

These changes bring unions up to speed with structs in terms of alignment and size resolution. The main goal of this PR was to resolve the circular dependency error you used to get when doing something like this:

constUnionInner=externstruct {
outer: UnionOuter=std.mem.zeroes(UnionOuter),
};
constUnion=externunion {
outer: ?*UnionOuter,
inner: ?*UnionInner,
};
constUnionOuter=externstruct {
u: Union=std.mem.zeroes(Union),
};
17287.zig:8:22: error: union '17287.Union' depends on itself
const Union = extern union {
~~~~~~~^~~~~
17287.zig:14:5: note: while checking this field
u: Union = std.mem.zeroes(Union),
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Since the fields are pointer types, there isn't actually a circular dependency here.

Changes:

  • Add resolveUnionAlignment, to resolve a union's alignment only, without triggering layout resolution.
  • Update resolveUnionLayout to cache size, alignment, and padding. abiSizeAdvanced and abiAlignmentAdvanced now use this information instead of computing it each time.
  • Resolve the false-positive circular dependency error when a union or struct uses @typeInfo on itself (such as std.mem.zeroes), when it has a field who's type refers to the containing type through a pointer.

@mlugg

mlugg commented Oct 12, 2023

Copy link
Copy Markdown
Member

I don't understand what the titular feature of this PR is doing. Clearly, in order to determine the ABI size of a union, we must know the size of all of its fields. Determining ABI size is a subset of layout resolution, so to resolve the former without resolving the latter (as is in the title of this PR) would imply that there exists some type whose size we can determine without fully resolving its in-memory layout. This seems contradictory to the whole idea of layout resolution. Do you have an example of such a case? (That is, a case where resolving a type's size requires less information than resolving its layout.)

@kcbanner
kcbannerforce-pushed the container_circular_dependency branch from 93d503c to 428f970CompareOctober 12, 2023 22:54
@kcbannerkcbanner changed the title sema: rework union layout resolution to resolve only the union's layout, instead of recursively resolving all fieldssema: Improvements to union and struct layout resolution to solve a false-positive circular dependency errorOct 12, 2023
@kcbanner

Copy link
Copy Markdown
ContributorAuthor

I don't understand what the titular feature of this PR is doing. Clearly, in order to determine the ABI size of a union, we must know the size of all of its fields. Determining ABI size is a subset of layout resolution, so to resolve the former without resolving the latter (as is in the title of this PR) would imply that there exists some type whose size we can determine without fully resolving its in-memory layout. This seems contradictory to the whole idea of layout resolution. Do you have an example of such a case? (That is, a case where resolving a type's size requires less information than resolving its layout.)

@mlugg Sorry, the original title was poor - it was the commit message of my initial changes before I really understood what was going on. I've updated the title and description now.

@kcbanner
kcbannerforce-pushed the container_circular_dependency branch 3 times, most recently from 88489bb to 981e001CompareOctober 13, 2023 05:32
- Add resolveUnionAlignment, to resolve a union's alignment only, without triggering layout resolution
- Update resolveUnionLayout to cache size, alignment, and padding
- Resolve a false-positive circular dependency error when a union or struct uses @typeinfo on itself (such as std.mem.zeroes)
@kcbanner
kcbannerforce-pushed the container_circular_dependency branch from 981e001 to 3a89324CompareOctober 13, 2023 05:32
@kcbanner
kcbanner marked this pull request as ready for review October 13, 2023 05:33
@kcbanner

Copy link
Copy Markdown
ContributorAuthor

For reviewer's reference (and as a justification for CircularComptimeRequirementCheck or something similar) this is stack of the error: union 'container_circular_dependency.Union' depends on itself error if you comment out all the return error.CircularComptimeRequirementCheck; that I've added.

zig.exe;resolveUnionLayout();7FF60D07BB90;6FBB90
zig.exe;resolveTypeLayout();7FF60CE08456;488456
zig.exe;typeAbiSize();7FF60D4BBC94;B3BC94
zig.exe;resolveStructLayout();7FF60D07A6D5;6FA6D5
zig.exe;resolveTypeLayout();7FF60CE083D2;4883D2
zig.exe;zirTypeInfo();7FF60D42D3E8;AAD3E8
zig.exe;analyzeBodyInner();7FF60D06A4F2;6EA4F2
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;analyzeBodyInner();7FF60D07904C;6F904C
zig.exe;analyzeBody();7FF60D38DD7F;A0DD7F
zig.exe;analyzeCall();7FF60D930E41;FB0E41
zig.exe;zirCall__anon_161264();7FF60D3F2E77;A72E77
zig.exe;analyzeBodyInner();7FF60D066F53;6E6F53
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;resolveBody();7FF60D9278CD;FA78CD
zig.exe;semaStructFields();7FF60D9F1257;1071257
zig.exe;resolveTypeFieldsStruct();7FF60D4C65E2;B465E2
zig.exe;comptimeOnlyAdvanced();7FF60D07EC26;6FEC26
zig.exe;comptimeOnlyAdvanced();7FF60D07E329;6FE329
zig.exe;typeRequiresComptime();7FF60CDF77DD;4777DD
zig.exe;hasRuntimeBitsAdvanced();7FF60D080C24;700C24
zig.exe;typeHasRuntimeBits();7FF60CDFAC6C;47AC6C
zig.exe;unionFieldHasRuntimeBits();7FF60D4C0344;B40344
zig.exe;resolveUnionLayout();7FF60D07BDB1;6FBDB1
zig.exe;resolveTypeLayout();7FF60CE08456;488456
zig.exe;zirTypeInfo();7FF60D42A75E;AAA75E
zig.exe;analyzeBodyInner();7FF60D06A4F2;6EA4F2
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;analyzeBodyInner();7FF60D07904C;6F904C
zig.exe;analyzeBody();7FF60D38DD7F;A0DD7F
zig.exe;analyzeCall();7FF60D930E41;FB0E41
zig.exe;zirCall__anon_161264();7FF60D3F2E77;A72E77
zig.exe;analyzeBodyInner();7FF60D066F53;6E6F53
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;resolveBody();7FF60D9278CD;FA78CD
zig.exe;semaStructFields();7FF60D9F1257;1071257
zig.exe;resolveTypeFieldsStruct();7FF60D4C65E2;B465E2
zig.exe;comptimeOnlyAdvanced();7FF60D07EC26;6FEC26
zig.exe;typeRequiresComptime();7FF60CDF77DD;4777DD
zig.exe;validateVarType();7FF60D901A07;F81A07
zig.exe;zirAllocMut();7FF60D3E1FFB;A61FFB
zig.exe;analyzeBodyInner();7FF60D065DD4;6E5DD4
zig.exe;resolveBlockBody();7FF60D9E509A;106509A
zig.exe;zirBlock();7FF60D4BB201;B3B201
zig.exe;analyzeBodyInner();7FF60D078DFE;6F8DFE
zig.exe;analyzeBody();7FF60D38DD7F;A0DD7F
zig.exe;analyzeFnBody();7FF60D045507;6C5507
zig.exe;ensureFuncBodyAnalyzed();7FF60CDF0FA4;470FA4
zig.exe;processOneJob();7FF60CDEEFBD;46EFBD
zig.exe;performAllTheWork();7FF60CC34098;2B4098
zig.exe;update();7FF60CC2F1F9;2AF1F9
zig.exe;updateModule();7FF60CC5DA65;2DDA65
zig.exe;buildOutputType();7FF60CC809E6;3009E6
zig.exe;mainArgs();7FF60CA9D8F1;11D8F1
zig.exe;main();7FF60CA9B16E;11B16E
zig.exe;main();7FF60CA9AE6A;11AE6A
zig.exe;__tmainCRTStartup();7FF60EFB56A6;26356A6
zig.exe;mainCRTStartup();7FF60EFB570C;263570C

@kcbanner

kcbanner commented Oct 21, 2023

Copy link
Copy Markdown
ContributorAuthor

After talking with @mlugg, I've decided to extra just the union alignment portion into #17658, and work on a different way to solve this circular dependency.

mlugg: So I think the best option is to introduce yet another resolution stage, where we resolve default inits after field types
mlugg: Here's a simple example of a dodgy case:

const S = struct { x: u32 = @alignOf(S) + 1 };

(The addition here is just to force us to resolve the lazy value)
This in theory is fine, right? We know from the field types that S has alignment 4, so x should have default value 5. However, because we try to resolve the inits at the same time as the field types, we can't know the alignment of S before we attempt to resolve the field init. In this case, it triggers the "guess pointer aligned" code, so S gets alignment 8

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Setting member default values causes false detection of a dependency loop @cImport "union depends on itself" regression

2 participants

@kcbanner@mlugg
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' sema: Improvements to union and struct layout resolution to solve a false-positive circular dependency error by kcbanner · Pull Request #17490 · ziglang/zig · GitHub
Skip to content

sema: Improvements to union and struct layout resolution to solve a false-positive circular dependency error - #17490

Closed
kcbanner wants to merge 1 commit into
ziglang:masterfrom
kcbanner:container_circular_dependency
Closed

sema: Improvements to union and struct layout resolution to solve a false-positive circular dependency error#17490
kcbanner wants to merge 1 commit into
ziglang:masterfrom
kcbanner:container_circular_dependency

Conversation

@kcbanner

@kcbannerkcbanner commented Oct 12, 2023

Copy link
Copy Markdown
Contributor

Fixes#17287
Fixes#17533

These changes bring unions up to speed with structs in terms of alignment and size resolution. The main goal of this PR was to resolve the circular dependency error you used to get when doing something like this:

constUnionInner=externstruct {
outer: UnionOuter=std.mem.zeroes(UnionOuter),
};
constUnion=externunion {
outer: ?*UnionOuter,
inner: ?*UnionInner,
};
constUnionOuter=externstruct {
u: Union=std.mem.zeroes(Union),
};
17287.zig:8:22: error: union '17287.Union' depends on itself
const Union = extern union {
~~~~~~~^~~~~
17287.zig:14:5: note: while checking this field
u: Union = std.mem.zeroes(Union),
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Since the fields are pointer types, there isn't actually a circular dependency here.

Changes:

  • Add resolveUnionAlignment, to resolve a union's alignment only, without triggering layout resolution.
  • Update resolveUnionLayout to cache size, alignment, and padding. abiSizeAdvanced and abiAlignmentAdvanced now use this information instead of computing it each time.
  • Resolve the false-positive circular dependency error when a union or struct uses @typeInfo on itself (such as std.mem.zeroes), when it has a field who's type refers to the containing type through a pointer.

@mlugg

mlugg commented Oct 12, 2023

Copy link
Copy Markdown
Member

I don't understand what the titular feature of this PR is doing. Clearly, in order to determine the ABI size of a union, we must know the size of all of its fields. Determining ABI size is a subset of layout resolution, so to resolve the former without resolving the latter (as is in the title of this PR) would imply that there exists some type whose size we can determine without fully resolving its in-memory layout. This seems contradictory to the whole idea of layout resolution. Do you have an example of such a case? (That is, a case where resolving a type's size requires less information than resolving its layout.)

@kcbanner
kcbannerforce-pushed the container_circular_dependency branch from 93d503c to 428f970CompareOctober 12, 2023 22:54
@kcbannerkcbanner changed the title sema: rework union layout resolution to resolve only the union's layout, instead of recursively resolving all fieldssema: Improvements to union and struct layout resolution to solve a false-positive circular dependency errorOct 12, 2023
@kcbanner

Copy link
Copy Markdown
ContributorAuthor

I don't understand what the titular feature of this PR is doing. Clearly, in order to determine the ABI size of a union, we must know the size of all of its fields. Determining ABI size is a subset of layout resolution, so to resolve the former without resolving the latter (as is in the title of this PR) would imply that there exists some type whose size we can determine without fully resolving its in-memory layout. This seems contradictory to the whole idea of layout resolution. Do you have an example of such a case? (That is, a case where resolving a type's size requires less information than resolving its layout.)

@mlugg Sorry, the original title was poor - it was the commit message of my initial changes before I really understood what was going on. I've updated the title and description now.

@kcbanner
kcbannerforce-pushed the container_circular_dependency branch 3 times, most recently from 88489bb to 981e001CompareOctober 13, 2023 05:32
- Add resolveUnionAlignment, to resolve a union's alignment only, without triggering layout resolution
- Update resolveUnionLayout to cache size, alignment, and padding
- Resolve a false-positive circular dependency error when a union or struct uses @typeinfo on itself (such as std.mem.zeroes)
@kcbanner
kcbannerforce-pushed the container_circular_dependency branch from 981e001 to 3a89324CompareOctober 13, 2023 05:32
@kcbanner
kcbanner marked this pull request as ready for review October 13, 2023 05:33
@kcbanner

Copy link
Copy Markdown
ContributorAuthor

For reviewer's reference (and as a justification for CircularComptimeRequirementCheck or something similar) this is stack of the error: union 'container_circular_dependency.Union' depends on itself error if you comment out all the return error.CircularComptimeRequirementCheck; that I've added.

zig.exe;resolveUnionLayout();7FF60D07BB90;6FBB90
zig.exe;resolveTypeLayout();7FF60CE08456;488456
zig.exe;typeAbiSize();7FF60D4BBC94;B3BC94
zig.exe;resolveStructLayout();7FF60D07A6D5;6FA6D5
zig.exe;resolveTypeLayout();7FF60CE083D2;4883D2
zig.exe;zirTypeInfo();7FF60D42D3E8;AAD3E8
zig.exe;analyzeBodyInner();7FF60D06A4F2;6EA4F2
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;analyzeBodyInner();7FF60D07904C;6F904C
zig.exe;analyzeBody();7FF60D38DD7F;A0DD7F
zig.exe;analyzeCall();7FF60D930E41;FB0E41
zig.exe;zirCall__anon_161264();7FF60D3F2E77;A72E77
zig.exe;analyzeBodyInner();7FF60D066F53;6E6F53
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;resolveBody();7FF60D9278CD;FA78CD
zig.exe;semaStructFields();7FF60D9F1257;1071257
zig.exe;resolveTypeFieldsStruct();7FF60D4C65E2;B465E2
zig.exe;comptimeOnlyAdvanced();7FF60D07EC26;6FEC26
zig.exe;comptimeOnlyAdvanced();7FF60D07E329;6FE329
zig.exe;typeRequiresComptime();7FF60CDF77DD;4777DD
zig.exe;hasRuntimeBitsAdvanced();7FF60D080C24;700C24
zig.exe;typeHasRuntimeBits();7FF60CDFAC6C;47AC6C
zig.exe;unionFieldHasRuntimeBits();7FF60D4C0344;B40344
zig.exe;resolveUnionLayout();7FF60D07BDB1;6FBDB1
zig.exe;resolveTypeLayout();7FF60CE08456;488456
zig.exe;zirTypeInfo();7FF60D42A75E;AAA75E
zig.exe;analyzeBodyInner();7FF60D06A4F2;6EA4F2
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;analyzeBodyInner();7FF60D07904C;6F904C
zig.exe;analyzeBody();7FF60D38DD7F;A0DD7F
zig.exe;analyzeCall();7FF60D930E41;FB0E41
zig.exe;zirCall__anon_161264();7FF60D3F2E77;A72E77
zig.exe;analyzeBodyInner();7FF60D066F53;6E6F53
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;resolveBody();7FF60D9278CD;FA78CD
zig.exe;semaStructFields();7FF60D9F1257;1071257
zig.exe;resolveTypeFieldsStruct();7FF60D4C65E2;B465E2
zig.exe;comptimeOnlyAdvanced();7FF60D07EC26;6FEC26
zig.exe;typeRequiresComptime();7FF60CDF77DD;4777DD
zig.exe;validateVarType();7FF60D901A07;F81A07
zig.exe;zirAllocMut();7FF60D3E1FFB;A61FFB
zig.exe;analyzeBodyInner();7FF60D065DD4;6E5DD4
zig.exe;resolveBlockBody();7FF60D9E509A;106509A
zig.exe;zirBlock();7FF60D4BB201;B3B201
zig.exe;analyzeBodyInner();7FF60D078DFE;6F8DFE
zig.exe;analyzeBody();7FF60D38DD7F;A0DD7F
zig.exe;analyzeFnBody();7FF60D045507;6C5507
zig.exe;ensureFuncBodyAnalyzed();7FF60CDF0FA4;470FA4
zig.exe;processOneJob();7FF60CDEEFBD;46EFBD
zig.exe;performAllTheWork();7FF60CC34098;2B4098
zig.exe;update();7FF60CC2F1F9;2AF1F9
zig.exe;updateModule();7FF60CC5DA65;2DDA65
zig.exe;buildOutputType();7FF60CC809E6;3009E6
zig.exe;mainArgs();7FF60CA9D8F1;11D8F1
zig.exe;main();7FF60CA9B16E;11B16E
zig.exe;main();7FF60CA9AE6A;11AE6A
zig.exe;__tmainCRTStartup();7FF60EFB56A6;26356A6
zig.exe;mainCRTStartup();7FF60EFB570C;263570C

@kcbanner

kcbanner commented Oct 21, 2023

Copy link
Copy Markdown
ContributorAuthor

After talking with @mlugg, I've decided to extra just the union alignment portion into #17658, and work on a different way to solve this circular dependency.

mlugg: So I think the best option is to introduce yet another resolution stage, where we resolve default inits after field types
mlugg: Here's a simple example of a dodgy case:

const S = struct { x: u32 = @alignOf(S) + 1 };

(The addition here is just to force us to resolve the lazy value)
This in theory is fine, right? We know from the field types that S has alignment 4, so x should have default value 5. However, because we try to resolve the inits at the same time as the field types, we can't know the alignment of S before we attempt to resolve the field init. In this case, it triggers the "guess pointer aligned" code, so S gets alignment 8

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Setting member default values causes false detection of a dependency loop @cImport "union depends on itself" regression

2 participants

@kcbanner@mlugg
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); sema: Improvements to union and struct layout resolution to solve a false-positive circular dependency error by kcbanner · Pull Request #17490 · ziglang/zig · GitHub
Skip to content

sema: Improvements to union and struct layout resolution to solve a false-positive circular dependency error - #17490

Closed
kcbanner wants to merge 1 commit into
ziglang:masterfrom
kcbanner:container_circular_dependency
Closed

sema: Improvements to union and struct layout resolution to solve a false-positive circular dependency error#17490
kcbanner wants to merge 1 commit into
ziglang:masterfrom
kcbanner:container_circular_dependency

Conversation

@kcbanner

@kcbannerkcbanner commented Oct 12, 2023

Copy link
Copy Markdown
Contributor

Fixes#17287
Fixes#17533

These changes bring unions up to speed with structs in terms of alignment and size resolution. The main goal of this PR was to resolve the circular dependency error you used to get when doing something like this:

constUnionInner=externstruct {
outer: UnionOuter=std.mem.zeroes(UnionOuter),
};
constUnion=externunion {
outer: ?*UnionOuter,
inner: ?*UnionInner,
};
constUnionOuter=externstruct {
u: Union=std.mem.zeroes(Union),
};
17287.zig:8:22: error: union '17287.Union' depends on itself
const Union = extern union {
~~~~~~~^~~~~
17287.zig:14:5: note: while checking this field
u: Union = std.mem.zeroes(Union),
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Since the fields are pointer types, there isn't actually a circular dependency here.

Changes:

  • Add resolveUnionAlignment, to resolve a union's alignment only, without triggering layout resolution.
  • Update resolveUnionLayout to cache size, alignment, and padding. abiSizeAdvanced and abiAlignmentAdvanced now use this information instead of computing it each time.
  • Resolve the false-positive circular dependency error when a union or struct uses @typeInfo on itself (such as std.mem.zeroes), when it has a field who's type refers to the containing type through a pointer.

@mlugg

mlugg commented Oct 12, 2023

Copy link
Copy Markdown
Member

I don't understand what the titular feature of this PR is doing. Clearly, in order to determine the ABI size of a union, we must know the size of all of its fields. Determining ABI size is a subset of layout resolution, so to resolve the former without resolving the latter (as is in the title of this PR) would imply that there exists some type whose size we can determine without fully resolving its in-memory layout. This seems contradictory to the whole idea of layout resolution. Do you have an example of such a case? (That is, a case where resolving a type's size requires less information than resolving its layout.)

@kcbanner
kcbannerforce-pushed the container_circular_dependency branch from 93d503c to 428f970CompareOctober 12, 2023 22:54
@kcbannerkcbanner changed the title sema: rework union layout resolution to resolve only the union's layout, instead of recursively resolving all fieldssema: Improvements to union and struct layout resolution to solve a false-positive circular dependency errorOct 12, 2023
@kcbanner

Copy link
Copy Markdown
ContributorAuthor

I don't understand what the titular feature of this PR is doing. Clearly, in order to determine the ABI size of a union, we must know the size of all of its fields. Determining ABI size is a subset of layout resolution, so to resolve the former without resolving the latter (as is in the title of this PR) would imply that there exists some type whose size we can determine without fully resolving its in-memory layout. This seems contradictory to the whole idea of layout resolution. Do you have an example of such a case? (That is, a case where resolving a type's size requires less information than resolving its layout.)

@mlugg Sorry, the original title was poor - it was the commit message of my initial changes before I really understood what was going on. I've updated the title and description now.

@kcbanner
kcbannerforce-pushed the container_circular_dependency branch 3 times, most recently from 88489bb to 981e001CompareOctober 13, 2023 05:32
- Add resolveUnionAlignment, to resolve a union's alignment only, without triggering layout resolution
- Update resolveUnionLayout to cache size, alignment, and padding
- Resolve a false-positive circular dependency error when a union or struct uses @typeinfo on itself (such as std.mem.zeroes)
@kcbanner
kcbannerforce-pushed the container_circular_dependency branch from 981e001 to 3a89324CompareOctober 13, 2023 05:32
@kcbanner
kcbanner marked this pull request as ready for review October 13, 2023 05:33
@kcbanner

Copy link
Copy Markdown
ContributorAuthor

For reviewer's reference (and as a justification for CircularComptimeRequirementCheck or something similar) this is stack of the error: union 'container_circular_dependency.Union' depends on itself error if you comment out all the return error.CircularComptimeRequirementCheck; that I've added.

zig.exe;resolveUnionLayout();7FF60D07BB90;6FBB90
zig.exe;resolveTypeLayout();7FF60CE08456;488456
zig.exe;typeAbiSize();7FF60D4BBC94;B3BC94
zig.exe;resolveStructLayout();7FF60D07A6D5;6FA6D5
zig.exe;resolveTypeLayout();7FF60CE083D2;4883D2
zig.exe;zirTypeInfo();7FF60D42D3E8;AAD3E8
zig.exe;analyzeBodyInner();7FF60D06A4F2;6EA4F2
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;analyzeBodyInner();7FF60D07904C;6F904C
zig.exe;analyzeBody();7FF60D38DD7F;A0DD7F
zig.exe;analyzeCall();7FF60D930E41;FB0E41
zig.exe;zirCall__anon_161264();7FF60D3F2E77;A72E77
zig.exe;analyzeBodyInner();7FF60D066F53;6E6F53
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;resolveBody();7FF60D9278CD;FA78CD
zig.exe;semaStructFields();7FF60D9F1257;1071257
zig.exe;resolveTypeFieldsStruct();7FF60D4C65E2;B465E2
zig.exe;comptimeOnlyAdvanced();7FF60D07EC26;6FEC26
zig.exe;comptimeOnlyAdvanced();7FF60D07E329;6FE329
zig.exe;typeRequiresComptime();7FF60CDF77DD;4777DD
zig.exe;hasRuntimeBitsAdvanced();7FF60D080C24;700C24
zig.exe;typeHasRuntimeBits();7FF60CDFAC6C;47AC6C
zig.exe;unionFieldHasRuntimeBits();7FF60D4C0344;B40344
zig.exe;resolveUnionLayout();7FF60D07BDB1;6FBDB1
zig.exe;resolveTypeLayout();7FF60CE08456;488456
zig.exe;zirTypeInfo();7FF60D42A75E;AAA75E
zig.exe;analyzeBodyInner();7FF60D06A4F2;6EA4F2
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;analyzeBodyInner();7FF60D07904C;6F904C
zig.exe;analyzeBody();7FF60D38DD7F;A0DD7F
zig.exe;analyzeCall();7FF60D930E41;FB0E41
zig.exe;zirCall__anon_161264();7FF60D3F2E77;A72E77
zig.exe;analyzeBodyInner();7FF60D066F53;6E6F53
zig.exe;analyzeBodyBreak();7FF60CE0F581;48F581
zig.exe;resolveBody();7FF60D9278CD;FA78CD
zig.exe;semaStructFields();7FF60D9F1257;1071257
zig.exe;resolveTypeFieldsStruct();7FF60D4C65E2;B465E2
zig.exe;comptimeOnlyAdvanced();7FF60D07EC26;6FEC26
zig.exe;typeRequiresComptime();7FF60CDF77DD;4777DD
zig.exe;validateVarType();7FF60D901A07;F81A07
zig.exe;zirAllocMut();7FF60D3E1FFB;A61FFB
zig.exe;analyzeBodyInner();7FF60D065DD4;6E5DD4
zig.exe;resolveBlockBody();7FF60D9E509A;106509A
zig.exe;zirBlock();7FF60D4BB201;B3B201
zig.exe;analyzeBodyInner();7FF60D078DFE;6F8DFE
zig.exe;analyzeBody();7FF60D38DD7F;A0DD7F
zig.exe;analyzeFnBody();7FF60D045507;6C5507
zig.exe;ensureFuncBodyAnalyzed();7FF60CDF0FA4;470FA4
zig.exe;processOneJob();7FF60CDEEFBD;46EFBD
zig.exe;performAllTheWork();7FF60CC34098;2B4098
zig.exe;update();7FF60CC2F1F9;2AF1F9
zig.exe;updateModule();7FF60CC5DA65;2DDA65
zig.exe;buildOutputType();7FF60CC809E6;3009E6
zig.exe;mainArgs();7FF60CA9D8F1;11D8F1
zig.exe;main();7FF60CA9B16E;11B16E
zig.exe;main();7FF60CA9AE6A;11AE6A
zig.exe;__tmainCRTStartup();7FF60EFB56A6;26356A6
zig.exe;mainCRTStartup();7FF60EFB570C;263570C

@kcbanner

kcbanner commented Oct 21, 2023

Copy link
Copy Markdown
ContributorAuthor

After talking with @mlugg, I've decided to extra just the union alignment portion into #17658, and work on a different way to solve this circular dependency.

mlugg: So I think the best option is to introduce yet another resolution stage, where we resolve default inits after field types
mlugg: Here's a simple example of a dodgy case:

const S = struct { x: u32 = @alignOf(S) + 1 };

(The addition here is just to force us to resolve the lazy value)
This in theory is fine, right? We know from the field types that S has alignment 4, so x should have default value 5. However, because we try to resolve the inits at the same time as the field types, we can't know the alignment of S before we attempt to resolve the field init. In this case, it triggers the "guess pointer aligned" code, so S gets alignment 8

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Setting member default values causes false detection of a dependency loop @cImport "union depends on itself" regression

2 participants

@kcbanner@mlugg